GitLab Container RegistryをKubernetesで使う
はじめに
以前GitLab Runner on Kubernetesに敗北した話 - てんぜんの生存日誌でお話したようにGitLabを実装しようとしましたが,諸所の都合で断念しました.
そこでSaaS版のGitLabを使用することにしたのですが,GitLab Container RegistryのプライベートリポジトリーにpushしたdockerイメージをKubernetes(k8s)でしようする方法をメモとして残しておきます.
準備
SaaS版GitLabのアカウントは以下から事前に作成しておいてください.
簡単に初期設定について書いておきます. まず,アカウントが作成できたら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鍵」へ進んでください.
進んだら,「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」に設定します.
正常にデプロイトークンが作成できたら図4のように表示されるはずです. (図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では可能)