GitLab Container RegistryをKubernetesで使う

はじめに

以前GitLab Runner on Kubernetesに敗北した話 - てんぜんの生存日誌でお話したようにGitLabを実装しようとしましたが,諸所の都合で断念しました.

そこでSaaS版のGitLabを使用することにしたのですが,GitLab Container RegistryのプライベートリポジトリーにpushしたdockerイメージをKubernetes(k8s)でしようする方法をメモとして残しておきます.

準備

SaaS版GitLabのアカウントは以下から事前に作成しておいてください.

gitlab.com

簡単に初期設定について書いておきます. まず,アカウントが作成できたらGitLabへSSH接続する設定 - Qiitaを参考にssh公開鍵の登録を行います.ここではMacを使用した場合の設定を行っていきます. sshのキー生成をしてない方は以下を実行してください.所持してる方は飛ばしてもらって構いません.

$ sshkey-gen -t ecdsa -b 521
$ ssh-add -K ~/.ssh/id_ecdsa
$ pbcopy < ~/.ssh/id_ecdsa.pub

次に先ほどコピーしたssh公開鍵をGitLabログイン後トップページ右上のユーザアイコンをクリックして,「設定>SSH鍵」へ進んでください.

right_button
図1:右上のユーザアイコン

進んだら,「SSH鍵を追加」のところにあるフォームに先ほどコピーした公開鍵をペーストして「キーを追加」ボタンを押します.

adding_ssh_key
図2:sshキーを追加

次に下記コマンドを実行して,「Welcome to GitLab, @ユーザ名!」と表示されれば登録成功です.

$ ssh -T git@gitlab.com
(省略)
Welcome to GitLab, @ユーザ名!

新規プロジェクトの作成

Webページで新規プライベートプロジェクトを作成したら,以前 Jupyter Lab on Kubernetesでの深層学習環境の構築 - てんぜんの生存日誌 の記事で作成したDockerfileを使用してGitLab Container Registryにpushしていきます.今回はGitLab CIを利用し,DockerfileをpushしたらGitLab側でDockerイメージを自動ビルドされるようにします.

まずはじめに作成したリポジトリをGit cloneしてきます. 今回はtestという名前のプロジェクトを作成しました. 新規プロジェクト作成時に「Initialize repository with a README」を選択しておくと以下のようにREADME.mdだけダウンロードされるはずです.

$ git clone git@gitlab.com:ユーザ名/test.git
$ cd test
$ ls
README.md

次に以下のようなDockerfileを自動ビルドしてくれるようなGitLab CIの設定ファイルである「.gitlab-ci.yaml」を作成します.

# This file is a template, and might need editing before it works on your project.
docker-build-master:
  # Official docker image.
  image: docker:latest
  stage: build
  services:
    - docker:dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE" .
    - docker push "$CI_REGISTRY_IMAGE"
  only:
    - master

docker-build:
  # Official docker image.
  image: docker:latest
  stage: build
  services:
    - docker:dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" .
    - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
  except:
    - master

DockerfileはJupyter Lab on Kubernetesでの深層学習環境の構築 - てんぜんの生存日誌で作成したものを流用してください.

後は以下のようにGitLab へpushしていきます.

$ git add Dockerfile
$ git add .gitlab-ci.yaml
$ git commit -m "deeplearning env"
$ git push origin master

pushしてWebページ左側の「リポジトリ>CI/CD>パイプライン」をみるとDockerビルドが実行されていることがわかります.正常にビルドできたら「パッケージ>コンテナレジストリ」にDockerイメージが追加されていること を確認してください.

Secretリソースの作成

k8sにおいてコンテナレジストリのプライベートリポジトリを使用する方法としては公式ドキュメントの Pull an Image from a Private Registry - Kubernetes でkubectlを使用して作成する方法が紹介されています. しかしCI/CDを使用する場合基本的にkubectlは使用しなかったりと,Secretリソースもマニフェストを作成して使用したい場合があります.

そこで今回はGitLabでアクセストークンを発行し,そのデプロイトークンを使用したSecretリソースのマニフェストを作成して,k8sでコンテナレジストリのプライベートレジストリのイメージを使用できるようにしていきます.

デプロイトークンの発行

先ほど作成したプライベートリポジトリのデプロイトークンを作成します. 図3のように左側サイドバーから「設定>CI/CD>デプロイトークン」にアクセスしてください.

その後デプロイトークンの名前,トークンを使用する際のユーザ名を入力してread_repogitryのチェックボックスにチェックをつっけてください. もし,トークンに有効期限を設けたい場合は,「Expires at」に設定します.

create_deploy_token
図3:デプロイトークンの発行

正常にデプロイトークンが作成できたら図4のように表示されるはずです. (図4に表示されているトークンは失効させているので使用できません.)

finish_createing_deploy_token
図4:デプロイトークンの発行完了

Secretリソースの作成

Secretリソースで使用する.dockerconfigjsonはbase64エンコードされている必要があるため,以下のようなシェルスクリプト「create_token.sh」を作成・実行することで,認証情報をbase64エンコードします.

UNAMEには先ほどデプロイトークンを作成する際に指定したユーザ名を,PASSには発行されたトークンを指定してください.

#!/bin/sh

UNAME=tenzen
PASS=mnjKVr_-r4eeN3Q-LWCH

AUTH=$(echo -n "${UNAME}:${PASS}" | base64)
SECRET=$(echo -n "{\"auths\":{\"registry.gitlab.com\":{\"username\":\"${UNAME}\",\"password\":\"${PASS}\",\"auth\":\"${AUTH}\"}}}")
echo -n ${SECRET} | base64

実行すると以下のように文字列が出力されるはずです.

$ bash create_token.sh
eyJhdXRocyI6eyJyZWdpc3RyeS5naXRsYWIuY29tIjp7InVzZXJuYW1lIjoidGVuemVuIiwicGFzc3dvcmQiOiJtbmpLVnJfLXI0ZWVOM1EtTFdDSCIsImF1dGgiOiJkR1Z1ZW1WdU9tMXVha3RXY2w4dGNqUmxaVTR6VVMxTVYwTkkifX19
$

作成した認証情報を以下のようなSecretマニフェスト「gitlab-tenzen-token.yaml」に埋め込みます.

apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyJyZWdpc3RyeS5naXRsYWIuY29tIjp7InVzZXJuYW1lIjoidGVuemVuIiwicGFzc3dvcmQiOiJtbmpLVnJfLXI0ZWVOM1EtTFdDSCIsImF1dGgiOiJkR1Z1ZW1WdU9tMXVha3RXY2w4dGNqUmxaVTR6VVMxTVYwTkkifX19
kind: Secret
metadata:
  name: gitlab-tenzen-token
  namespace: tenzen
  selfLink: /api/v1/namespaces/tenzen/secrets/gitlab-tenzen-token
type: kubernetes.io/dockerconfigjson

selfLinkは必要ないかもしれませんが,エラーがでる場合があるため適宜調整してください.

デプロイしておきます.

$ kubectl apply -f gitlab-tenzen-token.yaml

Secretリソースの利用

例えば前回 Jupyter Lab on Kubernetesでの深層学習環境の構築 - てんぜんの生存日誌 で作成したjupyterlab_deployment.yamlで,Image Pull用の認証情報を使用する場合は以下のように記述します.Image名はGitLabで作成したプロジェクトの左側サイドバーの「パッケージ>コンテナレジストリ」で確認することができます.今回は「registry.gitlab.com/tenzen/deeplearning:latest」になっています.

kind: Service
apiVersion: v1
metadata:
  name: jupyterlab-tenzen-clusterip
  namespace: tenzen
spec:
  type: ClusterIP
  selector:
    app: jupyterlab-tenzen
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8888
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: jupyterlab-config
  namespace: tenzen
data:
  jupyterlab-pass: "aiueo"
  jupyterlab-user-name: "tenzen"
  jupyterlab-user-id: "1000"
  jupyterlab-base-url: "/tenzen/"
  jupyterlab-home-dir: "/tenzen-pvc"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jupyterlab-deployment
  namespace: tenzen
  labels:
    app: jupyterlab-tenzen
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jupyterlab-tenzen
  template:
    metadata:
      labels:
        app: jupyterlab-tenzen
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                - key: hardware-type
                  operator: In
                  values:
                    - "NVIDIAGPU"
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 90
              preference:
                  matchExpressions:
                    - key: gpu-type
                      operator: In
                      values:
                        - "RTX2080Ti"
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
      containers:
      - name: jupyterlab-tenzen
+       image: registry.gitlab.com/tenzen/deeplearning:latest
        ports:
        - containerPort: 8888
        env:
        - name: JUPYTERLAB_PASS
          valueFrom:
            configMapKeyRef:
              name: jupyterlab-config
              key: jupyterlab-pass
        - name: UID
          valueFrom:
              configMapKeyRef:
                name: jupyterlab-config
                key: jupyterlab-user-id
        - name: USER_NAME
          valueFrom:
              configMapKeyRef:
                name: jupyterlab-config
                key: jupyterlab-user-name
        - name: BASE_URL
          valueFrom:
              configMapKeyRef:
                name: jupyterlab-config
                key: jupyterlab-base-url
        - name: HOME_DIR
          valueFrom:
              configMapKeyRef:
                name: jupyterlab-config
                key: jupyterlab-home-dir
        command:
        - "sh"
        - "-c"
        - | 
            PASSWORD=$(python -c 'from notebook.auth import passwd;print(passwd("'${JUPYTERLAB_PASS}'"))')
            jupyter-lab --port=8888 --ip=0.0.0.0 --no-browser --NotebookApp.token='' --NotebookApp.base_url=${BASE_URL} \
            --NotebookApp.password=${PASSWORD} --NotebookApp.notebook_dir=${HOME_DIR}
        volumeMounts:
          - mountPath: "/tenzen-pvc"
            name: tenzen-pvc
          - mountPath: /dev/shm
            name: dshm
        resources:
            limits:
              nvidia.com/gpu: 2
              cpu: 10000m
              memory: 64Gi
      volumes:
        - name: tenzen-pvc
          persistentVolumeClaim:
              claimName: tenzen-pvc
              readOnly: false
        - name: dshm
          emptyDir:
            medium: Memory
+     imagePullSecrets:
+       - name: gitlab-tenzen-token

補足(Dockerでの使用方法)

GitLab Container Registryに保存したImageはもちろんdockerでも使用できます. DockerHubのPrivate リポジトリの使用方法と同様に以下のようにログインしてpullするだけで使用することができます.

$ docker login registry.gitlab.com
$ docker pull registry.gitlab.com/tenzen/deeplearning:latest

注意点としてはリポジトリ名にアンダースコアやハイフンを含んでいるとdockerではイメージをPullすることができません.(k8sでは可能)

docs.gitlab.com