k3sでGitHub Container Registryにおいたプライベートなコンテナイメージをつかう
内容を整理していて気づいたが、本記事には
- (A) k3sでprivateなコンテナレジストリを使う
- (B) Github Package Registry (GPR)からGithub Container Registry (GHCR *1 )へ移行する
という2つのトピックが混ざっていることに気が付いた。備忘録も兼ねて先にアウトラインを示しておく。
(A) k3sでprivateなコンテナレジストリを使う
- k3sとは一言で表せばシングルバイナリの軽量Kubernetes
- エッジ環境やCIなどリソースが限られた状況を想定して作られている
- Rancher(kubernetesのめんどくさい設定をまるっと良しなにやってくれる君)を開発しているRancher社がk3sも開発している
- 本記事執筆中に公式ドキュメントの日本語訳をみつけた
- k3sは標準のコンテナランタイムとしてcontainerdを採用している
- ちなみにdockershim経由でdockerを使うことも可能
- k3sでprivateなコンテナレジストリを利用するにはk8sのそれとは異なる方法を取る必要がある
- じつはしばらくの間、containerdではGPRからdockerイメージをpullできない問題があった
- そのためk3sでprivteコンテナレジストリの設定を行ってもGPRからdockerイメージをpullできなかった
- 問題の原因はGithub側にあったのだが、2020年にGPRのdockerイメージレジストリがGHCRへと切り出された際に解決した
- ref. containerd can't pull image from Github Docker Package Registry · Issue #3291 · containerd/containerd · GitHub
(B) Github Package Registry (GPR)からGithub Container Registry (GHCR)へ移行する
- Github Package RegistryとはGithub社で提供しているパッケージレジストリ
- Github Actionsと組み合わることでコードベース管理からレジストリ登録までgithubで完結できる
- Github Container Registryとは同じくGithub社が提供するコンテナレジストリ
- オフィシャルアナウンス曰く、
GitHub Container Registry improves how we handle containers within GitHub Packages. With the new capabilities introduced today, you can better enforce access policies, encourage usage of a standard base image, and promote innersourcing through easier sharing across the organization.
- とのことだが、後述するとおり基本的にはGPRでDocker imageをホスティングするのと使い方は大きく変わらない。DockerHubやAmazon Elastic Container Registryなどと同じ位置づけ
- まだpublic beta段階なので利用するには機能の有効化が必要
- publicなコンテナイメージに対しては無料利用でき、public bataのフェーズの間はprivateなものも無料で利用できる。generally availableになったあともGPRと同じ課金モデルで提供予定とのこと
- オフィシャルアナウンス曰く、
- Github Actionをつかってdockerイメージをビルド、およびGHCRへイメージをpushするならdocker/build-push-actionを使うのが簡単
- github.com
- GHCRにpushするにはコンテナイメージのtagは
ghcr.io/
接頭辞としてもつ必要がある
ここで今一度、takeawayを要約すると
- Github Container Registry (GHCR)に置いたprivateコンテナイメージならk3sから利用できる
- docker/build-push-action@v2を使ってGHCRにコンテナイメージをpushするには、(1)事前に機能の有効化を行い、(2)tagには
ghcr.io/
接頭辞としてつける
ということになる。
それでは次から具体的な方法を示していく。
ちなみにk3sはARMでも動くと謳っているが、本記事ではx86系のプロセッサで動く環境を前提とする*2。 本記事で利用したコードをこちらのリポジトリにまとめた。
1. Github Actionを用いたGHCRへのコンテナイメージ登録
流れとしては以下の4ステップ。
- 1-a. 適当なプログラムとDockerイメージを生成するDockerfileの用意
- 1-b. GHCRの有効化
- 1-c. GHCRの認証用にPAT(Private Access Token)の発行
- 1-d. GithubActionでdocker/build-push-action@v2を使うための設定
基本的にはリファレンスを張りつつ注意書き程度の補足を記すが、サンプルコードと合わせて確認してもらいたい。
1-a. 適当なプログラムとDockerイメージを生成するDockerfileの用意
Hello!の文字列と現在時刻を4秒ごとに履き続けるjsスクリプトをDockerイメージとして用意する。 長々と述べるよりもcommitログを見るほうがわかりやすいように思う。
1-b. GHCRの有効化
オフィシャルドキュメントにて画像添付で解説されているので参考にされたい。PersonalとOrganizationとで有効化ボタンが2箇所あるので注意。
なお、これを忘れると後述するGHCRへのコンテナイメージpushが失敗する。
1-c. GHCRの認証用にPAT(Private Access Token)の発行
オフィシャルでGITHUB_TOKEN
ではなくPATを利用するように書かれている。
If you want to authenticate to GitHub Container Registry in a GitHub Actions workflow, then you must use a personal access token (PAT).
PATの作成方法はこちらから。
作成したPATをセキュアにGithub Actionに渡すには secrets
という仕組みを利用する。
PATとは異なり、secretsはリポジトリごとあるいはOrganizationごとに登録する。登録した値をGithub Actionから${{ secrets.SuperSecret }}
のようにして参照する。
1-d. GithubActionでdocker/build-push-action@v2を使うための設定
v1
から v2
へとアップデートした際に大きな仕様変更があり、v2
では レジストリログイン と ビルド環境セットアップが別actionに切り出された。
とはいえ設定項目が難しくなった訳でもないので素直にREADME.mdに従ってworkflowを書けば良い。
なお、v1
にあった便利な tag_with_ref
が使えなくなってしまった。そのためコンテナイメージへのタグ付けは他のアクションで賄う必要がある*3。
name: deploy on: push: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to GitHub Container Registry uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GHCR_PAT }} # secret経由でPATを渡す - name: Get smart tag # このstepはオプショナル。v1の`tag_with_ref`と同等の機能 id: prepare uses: Surgo/docker-smart-tag-action@v1 with: docker_image: ghcr.io/${{ github.repository }}/test # `ghcr.io`を接頭辞にすること - name: Build and push uses: docker/build-push-action@v2 with: push: true context: . tags: ${{ steps.prepare.outputs.tag }} # 前ステップ(prepare)で用意したタグ名を使う build-args: NODEJS_VERSION=14.10.0-slim cache-from: type=registry,ref=ghcr.io/${{ github.repository }}/test:develop cache-to: type=inline
2. Privateレジストリの設定とk3sのインストール
k3sでプライベートレジストリを利用するには、事前に所定のパスに設定ファイルを配備する*4。具体的には /etc/rancher/k3s/registries.yaml
に以下の内容でファイルを置く。
$ cat /etc/rancher/k3s/registries.yaml mirrors: ghcr: endpoint: - "https://ghcr.io" configs: "ghcr.io": auth: username: sat0yu password: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
username
にはGithubアカウント、password
にはPATを指定する。ここで使うPATは read:packages
権限があれば十分で、GHCRにコンテナイメージをPushするときのものと異なっていても良い(むしろ別にしたほうが安全。)
オフィシャルドキュメントを見るとhttps
ならTLSに関する設定が必須のように誤解しそうだが、上記のようにTLSフィールドを省略しても正常にイメージをpullできた。
registries.yaml
が用意できたらk3sのインストールを行う。k3sのインストールはワンライナーで済む。
$ curl -sfL https://get.k3s.io | sh - [INFO] Finding release for channel stable [INFO] Using v1.20.0+k3s2 as release [INFO] Downloading hash https://github.com/rancher/k3s/releases/download/v1.20.0+k3s2/sha256sum-amd64.txt [INFO] Downloading binary https://github.com/rancher/k3s/releases/download/v1.20.0+k3s2/k3s [INFO] Verifying binary download [INFO] Installing k3s to /usr/local/bin/k3s [INFO] Creating /usr/local/bin/kubectl symlink to k3s [INFO] Creating /usr/local/bin/crictl symlink to k3s [INFO] Skipping /usr/local/bin/ctr symlink to k3s, command exists in PATH at /usr/bin/ctr [INFO] Creating killall script /usr/local/bin/k3s-killall.sh [INFO] Creating uninstall script /usr/local/bin/k3s-uninstall.sh [INFO] env: Creating environment file /etc/systemd/system/k3s.service.env [INFO] systemd: Creating service file /etc/systemd/system/k3s.service [INFO] systemd: Enabling k3s unit Created symlink /etc/systemd/system/multi-user.target.wants/k3s.service → /etc/systemd/system/k3s.service. [INFO] systemd: Starting k3s
k3sはkubectl
が同梱していて、正常にインストール完了するとkubectl
コマンドにsymlinkがはられる。
kubectl get node
で動作を確認しておく。
$ ls -al /usr/local/bin/kubectl lrwxrwxrwx 1 root root 3 Jan 18 14:06 /usr/local/bin/kubectl -> k3s $ sudo kubectl get node NAME STATUS ROLES AGE VERSION xxxx Ready control-plane,master 32s v1.20.0+k3s2
3. k3sクラスタへのpodデプロイ
全ステップまでですでにk3sクラスタ*5を立ち上げた状態になっている。
マニフェストファイルに特別な記述は必要なく、適切なimageを指定すれば良い。
apiVersion: apps/v1 kind: Deployment metadata: name: test spec: replicas: 1 selector: matchLabels: app: test template: metadata: labels: app: test spec: containers: - name: test image: ghcr.io/sat0yu/k3s-with-private-container-images-in-gcr/test:master imagePullPolicy: Always command: ["yarn", "start"]
あとはマニフェストファイルをapplyしてk8sがコンテナイメージをpullしてデプロイが完了させる。
$ sudo kubectl apply -f deployment.yaml deployment.apps/test configured
最後に期待通りコンテナが動いているか確認する
$ sudo kubectl get po NAME READY STATUS RESTARTS AGE test-85b8b88944-grmsk 1/1 Running 0 2m22s $ sudo kubectl logs -f -l app=test hello! Mon Jan 18 2021 23:44:58 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:02 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:06 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:10 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:14 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:18 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:22 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:26 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:30 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:34 GMT+0000 (Coordinated Universal Time) hello! Mon Jan 18 2021 23:45:38 GMT+0000 (Coordinated Universal Time)
*1:GCRだとContainer Registry | Google Cloudと紛らわしい
*2:確認していないがDockerfileにあるnodeのベースイメージを適切なものに変更すればARMでも動くと思う
*3:サンプルコードではSurgo/docker-smart-tag-actionを利用した
*4:マニュアルによればk3s起動時に--private-registryオプションでパスを指定することも可能らしい
*5:k3sで立ち上げるk8sクラスタ?