自宅サーバ環境で Kubernetes のイメージを自動更新するCIワークフローを構築する方法を紹介します.
やりたいこと
git push
した際,次の3点を自動で行いたい.
- テスト
- コンテナイメージのビルドおよびコンテナレジストリへの登録
- Kubernets 上の Pod のイメージ更新
この際,テストやコンテナイメージの中においては,一般公開したくないデータを気軽に扱えるようにしたいので,自宅サーバでシステム構築することにします.
前提と道具立て
自宅サーバーでのシステム構築するにあたり,下記の前提をおきます.
- 自宅サーバー内で Kubernetes クラスタが既に動いている (参考:『Ubuntu 22.04 に Kubernetes をインストールして自宅クラウド』)
- 自宅サーバー内の各種サービスは基本的にインターネットに公開しない
- TLS が必要な場合,プライベート認証局が発行した証明書を使用する
2番目の項目はセキュリティを維持して運用するコストが無視しがたいためです.この前提の元だと,Let’s Encrypt とかが使えなくなるので,自動的に3番目の者の前提が発生します.
以上を踏まえ,使用するソフトと目的は下記とします.
- GitLab
- git を軸にした CI ワークフローを回すのに使用します.Docker で動かします.
- Docker registry
- Kubernetes クラスタ上で動かすコンテナイメージを格納するのに使います.Docker で動かします.
- GitLab Runnner
- GitLab CI ジョブを走らせるために使用します.Kubernetes クラスタ上で動かします.
- GitLab Agent for Kubernetes
- GitLab CI ジョブの中から Kubernetes クラスタに対して
kubectl
コマンドを実行するのに使用します.Kubernetes クラスタ上で動かします.
GitLab と Docker registry は Kubernetes 上で動かすこともでききます.ただ,自宅で Kubernetes を運用する場合はバージョンアップ時にクラスタを再構築する可能性があるので,今回はクラスタ外に設置しました.
Docker registry は GitLab のコンテナの中にはいっているものを使っても良いのですが,GitLab 関連でトラブった際にもレジストリは正常稼働させたいので,今回は別に設定します.
ESXi 等を使って,専用の仮想サーバを立ててその中で Docker を動かすと良いと思います.
なお,Kubernetes のイメージを自動更新する方法としては,Argo CD Image Updater という手段もよく使われているようなのですが,GitLab CI のフローの中で完結させた方が分かりやすいので、今回は GitLab Agent for Kubernetes の方を採用しました.
準備
GitLab Agent for Kubernetes を使うには,GitLab を HTTPS でアクセスできるようにしないといけないので,準備としてプライベートCA(認証局) を作って,サーバー証明書を発行しておきます.
作業手順は以下の通りです.「gitlab.green-rabbit.net」の部分はお手元の環境に置き換えてください.
何をやっているかは参考文献のリンク先が詳しいです.
-
プライベート CA の運用をサポートしてくれる Easy-RSA をインストール.
1$ sudo apt-get install easy-rsa -
作業用のディレクトリを準備.
123$ mkdir local-ca$ cd local-ca$ ln -s /usr/share/easy-rsa/* . -
設定ファイルを準備.
1234567$ echo "set_var EASYRSA_ALGO ecset_var EASYRSA_CURVE secp384r1set_var EASYRSA_CA_EXPIRE 36500set_var EASYRSA_CERT_EXPIRE 36500set_var EASYRSA_CRL_DAYS 36500" > vars$ export EASYRSA_VARS_FILE=$(pwd)/vars -
プライベートCA(認証局) を初期化.
12$ ./easyrsa init-pki$ ./easyrsa build-ca nopass -
サーバー用の証明書を発行.
123$ openssl genrsa -out gitlab.green-rabbit.net.key$ openssl req -new -key gitlab.green-rabbit.net.key -out gitlab.green-rabbit.net.req$ ./easyrsa sign-req server gitlab.green-rabbit.net nopass
使用するのは生成された次の3つのファイルです.
- pki/ca.crt
- プライベートCA(認証局) のルート証明書.分かりやすいように,名前を local-ca.crt に変更しておきます.
GitLab コンテナ,GitLab Runner,GitLab Agent にて使用します.
今回は紹介しませんが,Windwos の「信頼されたルート証明機関」に追加することで,ブラウザで表示したときに警告が出なくなります. - pki/issued/gitlab.green-rabbit.net.crt
- サーバ証明書.
GitLab コンテナで使用します. - gitlab.green-rabbit.net.key
- サーバー秘密鍵.
GitLab コンテナで使用します.
インストールと設定
以降で必要なソフトのインストール手順を準備説明します.
先ほどと同様に「gitlab.green-rabbit.net」の部分は GitLab を設定するホスト名に置き換えてください.
GitLab
-
カスタムイメージを作成します.
GitLab Agent を動かすには GitLab が HTTPS でアクセスできる必要があるのですが,
現状だと GitLab のコンテナの中で動く GitLab Agent Server にプライベートCAのルート証明書を渡す方法がありません.よって,証明書をシステムに仕込んだイメージを作成します.12345$ echo "FROM gitlab/gitlab-ee:15.10.7-ee.0COPY local-ca.crt /usr/local/share/ca-certificates/RUN update-ca-certificates" > Dockerfile$ docker build . -t gitlab-ee-local:15.10.7-ee.0「rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL」という警告がでますが,無視して OK です.
-
ディレクトリと TSL 用のファイルを準備します.
1234$ mkdir -p config logs data ssl$ cp -f "先ほど作った local-ca.crt" ./ssl$ cp -f "先ほど作った gitlab.green-rabbit.net.crt" ./ssl$ cp -f "先ほど作った gitlab.green-rabbit.net.key" ./ssl -
下記の内容の
docker-compose.yml
を作成します.
12345678910111213141516171819202122232425262728293031323334version: '3.6'services:gitlab:image: gitlab-ee-local:15.10.7-ee.0restart: alwayshostname: 'gitlab.green-rabbit.net'environment:GITLAB_OMNIBUS_CONFIG: |external_url "https://gitlab.green-rabbit.net"registry_external_url "http://registry.green-rabbit.net:5000"letsencrypt['enable'] = falsegitlab_rails['registry_enabled'] = truegitlab_rails['registry_api_url'] = "http://registry.green-rabbit.net:5000"gitlab_rails['gitlab_shell_ssh_port'] = 8022nginx['enable'] = truenginx['listen_port'] = 443nginx['redirect_http_to_https'] = truenginx['ssl_certificate'] = "/etc/gitlab/ssl/gitlab.green-rabbit.net.crt"nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/gitlab.green-rabbit.net.key"ports:- '80:80'- '443:443'- '8022:22'volumes:- ./config:/etc/gitlab- ./logs:/var/log/gitlab- ./data:/var/opt/gitlab- ./ssl:/etc/gitlab/sslshm_size: '256m'registry_external_url
は,後ほど設置する Docker registry のアドレスを記載しておきます.メールの送信とかにも対応したい場合,下記を見ながら適宜追加を行います.
Configuring a Linux package installation | GitLabGitLab product documentation. - 下記のコマンドで起動します.サイトがアクセスできるようになるまで,5分前後かかります.
1$ docker-compose up -d - GitLab にアクセスできるようになったら,下記のコマンドで初期パスワード確認し,ユーザ名 root ログインします.
1$ docker exec gitlab_gitlab_1 cat /etc/gitlab/initial_root_password
Docker registry
設置は下記の内容の docker-compose.yml
を作成し,docker-compose up
すればOK.
1 2 3 4 5 6 7 |
registory: container_name: docker-registory image: registry:2.8 ports: - 5000:5000 volumes: - ./data:/var/lib/registry |
上記のようにすると HTTPS ではなく,HTTP でアクセスする形になるので,コンテナイメージを扱うホスト全てで,次の設定をしておきます.「registry.green-rabbit.net」は Docker registry を設置したホスト名です.お手元の環境に合わせて読み替えてください.
/etc/docker/daemon.json
-
次の内容でファイルを作成します.
1{"insecure-registries": ["registry.green-rabbit.net:5000"]}
もし,既に設定されたホストがある場合は下記のように追加します.
1{"insecure-registries": ["registry.green-rabbit.net", "registry.green-rabbit.net:5000"]} /etc/containerd/config.toml
-
「[plugins.”io.containerd.grpc.v1.cri”.registry]」という行の少しあとに,4行追加します.
1234567891011121314[plugins."io.containerd.grpc.v1.cri".registry]config_path = ""[plugins."io.containerd.grpc.v1.cri".registry.auths][plugins."io.containerd.grpc.v1.cri".registry.configs]+ [plugins."io.containerd.grpc.v1.cri".registry.configs."registry.green-rabbit.net:5000".tls]+ insecure_skip_verify = true[plugins."io.containerd.grpc.v1.cri".registry.headers][plugins."io.containerd.grpc.v1.cri".registry.mirrors]+ [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.green-rabbit.net:5000"]+ endpoint = ["http://registry.green-rabbit.net:5000"]
終わったら containerd を再起動しておきます.
1 |
$ sudo systemctl restart containerd |
GitLab Runnner
基本的には下記の「Install on Kubernetes」に従えば OK です.
具体的な手順を紹介します.
-
Operator を使ってインストールします.(Helm でインストールする方法もあります)
123$ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.yaml$ curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.24.0/install.sh | bash -s v0.24.0$ kubectl create -f https://operatorhub.io/install/gitlab-runner-operator.yaml
次のように,「Succeeded」となっていればインストール成功です.
123$ kubectl get csv -n operatorsNAME DISPLAY VERSION REPLACES PHASEgitlab-runner-operator.v1.14.0 GitLab Runner 1.14.0 gitlab-runner-operator.v1.13.0 Succeeded -
下記のマニフェストを作成して
kubectl apply
します.1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950apiVersion: v1kind: Secretmetadata:name: gitlab-runner-secretnamespace: servertype: OpaquestringData:runner-registration-token: XXXXXXXXXXXXXXXXXXXX---apiVersion: v1kind: Secretmetadata:name: gitlab-tls-canamespace: servertype: OpaquestringData:tls.crt: |-----BEGIN CERTIFICATE-----【local-ca.crt の中身】-----END CERTIFICATE--------apiVersion: v1kind: ConfigMapmetadata:name: gitlab-runner-confignamespace: serverdata:config.toml: |[[runners]][runners.kubernetes]privileged=trueimage="docker:23.0-dind"[[runners.kubernetes.volumes.host_path]]name="docker"read_only=truemount_path="/var/run/docker.sock"host_path="/var/run/docker.sock"---apiVersion: apps.gitlab.com/v1beta2kind: Runnermetadata:name: gitlab-runnernamespace: serverspec:gitlabUrl: https://gitlab.green-rabbit.net/buildImage: alpinetoken: gitlab-runner-secretconfig: gitlab-runner-configca: gitlab-tls-caconcurrent: 4runner-registration-token
には,「Register an instance runner」で取得したトークンを指定します.管理者用メニューを [CI/CD] – [Runners] と辿っていくと右側にでてきます.「kind: Secret」には,プライベートCA のルート証明書 local-ca.crt の中身を貼り付けます.
[runners.kubernetes] 以降の設定は,CI の中で
docker
コマンドを実行するのに必要になります.
GitLab Agent for Kubernetes
このステップは,GitLab で管理しているプロジェクト毎に実施するので,事前になにかプロジェクトを作っておきます.
作業としては,基本的に下記の「Register the agent with GitLab」に従えば OK です.
具体的な手順を紹介します.
-
チェックアプトしたプロジェクトに,「.gitlab/agents/[任意の名前]」というファイルを作成し,
git commit && git push
します.[任意の名前] の部分はアルファベット小文字と「-」で構成されていれば何でもOKです.アンダーバー「_」は使えないので注意. - プロジェクトの右側のメニューを [Infrastructure] – [Kubernetes clusters] – [Connect a cluster] と辿っていくと,先ほど追加した[任意の名前] が出てくるので選択肢,Register をクリックします.(下図は,「pod-rollout」というファイル名にしていた場合)
-
下記のように表示されるので赤枠の部分をコピー.
-
kubectl
が実行できる環境で,先ほどコピーしたコマンドの末尾に「–set-file config.caCert=/path/to/local-ca.crt」を付けて実行します.「/path/to/local-ca.crt」の部分はプライベートCAのルート証明書のパスに読み替えてください.1% helm upgrade --install pod-rollout gitlab/gitlab-agent --namespace gitlab-agent-pod-rollout --create-namespace --set image.tag=v15.11.0 --set config.token=5UBwZ-dfHEwie1-gscDyUU4uz5e7K_xBUqGxuYFz-DBxpBKmBw --set config.kasAddress=wss://gitlab.green-rabbit.net/-/kubernetes-agent/ --set-file config.caCert=/home/kimata/local-ca.crt - 先ほどの GitLab のページで下記のように Connected となっていれば成功です
テスト
先ほど Agent を登録したプロジェクトのトップに .gitlab-ci.yml という名前で次のよう内容のファイルを作成します.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
image: docker:23.0 stages: - test deploy: stage: test image: name: bitnami/kubectl:latest entrypoint: [''] script: - kubectl config get-contexts - kubectl config use-context kimata/e-ink_weather_panel:pod-rollout - kubectl --insecure-skip-tls-verify=true get pods -A |
「kimata/e-ink_weather_panel:pod-rollout」の部分は下記で読み替えてください.
- コロンの前は GitLab のリポジトリのパス
- コロンの後ろは Agent を登録するときに使った名前
これによって先ほど登録した Agent 経由で Kubernetes クラスタを操作できるようになります.
git commit && git push
してからしばらく待って,プロジェクトの右側のメニューを [CI/CD] – [Jobs] と辿り,「passed」と表示されていれば成功です.
なお,kubectl
を実行する際に --insecure-skip-tls-verify=true
を付けたくない場合は,GitLab のイメージにプライベートCAのルート証明書を追加したのと同様の作業を bitnami/kubectl:latest のイメージに対して行い,そちらのイメージを使うようにすれば OK です.
ハマったポイント
GitLab Agent for Kubernetes のアーキは,GitLab が HTTPS でインターネットで公開されていることを前提としており,プライベートCAのルート証明書を扱う想定をしていないので動くようになるまで苦労しました.
上手くいかない場合「x509: certificate signed by unknown authority 」というエラーが出るのですが,このエラーを出すのが CI ジョブ上の kubectl
だけでなく,GitLab イメージ内の GitLab agent server for Kubernetes (KAS) にもあることに気付けるかどうかが鍵でした.
GitLab Agent for Kubernetes のリポジトリにある下記のアーキ図を眺めていたら全てが繋がった感じです.
上の図において kas から GitLab RoR に矢印が伸びているのがポイントです.既存の公式ドキュメントでは,agentk から伸びる矢印でプライベートCAのルート証明書を使う方法(--set-file config.caCert
)は書かれていても,このアクセスにおいてが記載されていません.あとは,agentk と kas のソースコードをざっと比較して全てを悟りました.
一応,解決方法は本家のフォーラムにも投げてあります.もしかしたら,私の思い違いとかがあって,もっと良い方法がでてくるかも.
参考文献
- easy-rsaでプライベートCA(認証局)を作ってオレオレ証明書ではないローカル用TLS証明書の管理をする
- プライベートCAを使った証明書の発行についてわかりやすく解説されています.
- GitLabにpushされたらGitHubのリポジトリにも反映させる!(ミラーリング)
- ローカルの GitLab から GitHub にリポジトリを同期する方法が紹介されています.
ローカルの GitLab に移行すると,リポジトリの完全性をどう保守していくかが気になりますが,ここで紹介されている方法を使えば自動的に同期させるのでそうした心配も不要になります.GitHub のリポジトリのアドレスを指定するときに HTTPS を使い,ユーザー名を入れるのがポイントです.(GitHub から
git clone
する際のアドレスだとユーザ名が入っていないので注意)
コメント