LoginSignup
7
3

More than 1 year has passed since last update.

GitlabとKanikoによるコンテナの自動ビルド&配布環境の構築

Last updated at Posted at 2023-03-29

Introduction

自分用のCI(Continuous Integration)環境やコンテナレジストリが欲しいと思ったことはありませんか?
「ある」と思った人に向けて、今回はGitlab CIを使ったコンテナの自動ビルド環境&配布環境を作るのに何が必要なのか、順番に見ていきます。

コンテナのビルドに使用するKanikoは、Dockerデーモンに依存せずにDockerfile内のコマンドをユーザースペースで実行することで、標準的なKubernetesクラスタや特権無しのDockerデーモンでもコンテナをビルド出来るようにするツールです。
Gitlab runnerでDocker privilegedを使いたくないケースもありますからね。

GitlabとKanikoについての詳しい説明は公式ドキュメントを参照ください。

なお、このドキュメントに出てくるパスワードやトークンは文書を書くためだけに作られている例なので気にしないでください。

Environment

以下の2台の仮想マシンを準備します。どちらも Ubuntu 20.04のクラウドイメージ を使用します。

  • qiita-gitlab: Gitlabをインストールするノード
  • qiita-runner: Gitlab runnerをインストールするノード

Install Gitlab omunibus

まずは https://about.gitlab.com/install/#ubuntu に沿ってGitlab-EEをインストールします。
Ubuntu 20.04のクラウドイメージは最初から前提となるパッケージが揃っているので、少し省略します。
作業は qiita-gitlab ノードで実施します。

curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash
export EXTERNAL_URL="http://qiita-gitlab.example.com"
export GITLAB_ROOT_PASSWORD="ILTTqnDv4iBxKwt5UWzc/rOeEkk1AO/6QzjfK+cS0Pw="
sudo -E apt-get install gitlab-ee

http://qiita-gitlab.example.com はこの文書のためのURLです。
お使いの環境に合わせて変更してください。
変更しない場合は各ノードのhostsに qiita-gitlab.example.com を設定してアクセスできるようにしましょう。(手順外)

また EXTERNAL_URLhttps://... で作成すると自動的にLet’s Encryptで証明書を取得するサポート機能があるようですが、今回は使用しません。

ログイン出来たらOKです。

image.png

で、ログイン。

image.png

Gitlabのインストールは問題なさそうです。

パスワードの要件 は結構厳しく、適合しないとrootユーザーが作成されません。
rootユーザーが作成されなかった場合は、別途 /etc/gitlab.rbgitlab_rails['initial_root_password'] を編集して gitlab-ctl reconfigure を実行するなどして対応します。

インストールされたバージョンは以下の通りです。

$ sudo gitlab-rake gitlab:env:info

System information
System:         Ubuntu 20.04
Proxy:          no
Current User:   git
Using RVM:      no
Ruby Version:   3.0.5p211
Gem Version:    3.2.33
Bundler Version:2.3.15
Rake Version:   13.0.6
Redis Version:  6.2.8
Sidekiq Version:6.5.7
Go Version:     unknown

GitLab information
Version:        15.10.0-ee
Revision:       defe6e7f882
Directory:      /opt/gitlab/embedded/service/gitlab-rails
DB Adapter:     PostgreSQL
DB Version:     13.8
URL:            http://qiita-gitlab.example.com
HTTP Clone URL: http://qiita-gitlab.example.com/some-group/some-project.git
SSH Clone URL:  git@qiita-gitlab.example.com:some-group/some-project.git
Elasticsearch:  no
Geo:            no
Using LDAP:     no
Using Omniauth: yes
Omniauth Providers: 

GitLab Shell
Version:        14.18.0
Repository storages:
- default:      unix:/var/opt/gitlab/gitaly/gitaly.socket
GitLab Shell path:              /opt/gitlab/embedded/service/gitlab-shell

Create Gitlab project

それでは、適当なプロジェクトを作成しましょう。
まずは新規プロジェクトを選択。

image.png

Create blank projectを選択。

image.png

今回は gitlab-ci-sample というプロジェクト名にしました。
初期のREADME.md作成はOFFにしましたが、説明の簡略化のためなのでどちらでも構いません。

image.png

これでプロジェクトが作成されて、以下の状態になりました。

image.png

Project settings

Gitlan runnerに登録するProject専用のRegistration keyを取得します。
Settings -> CI/CD を開いて、

image.png

Runnerを選択するとプロジェクト専用のregistration tokenが取得できます。
Gitlab runnerの登録時に、このトークンを使用するのでメモしておきます。

image.png

ついでに、デフォルトで有効になっているAuto DevOpsは、今回作成するCI設定範囲の分かりやすさのため無効にしておきます。

image.png

Install Gitlab runner

次はDocker用のGitlan runnerを準備しましょう。
作業は qiita-runner ノードで実施します。

Install docker for gitlab-runner docker executor

まずは https://docs.docker.com/engine/install/ubuntu/ に沿ってDocker Engineをインストールします。
こちらも、Ubuntu 20.04のクラウドイメージは最初から前提となるパッケージが揃っているので、少し省略します。

sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Dockerのバージョンは以下の通りです。
DockerはGitlab runnerでKanikoコンテナを動かすために使います。

$ sudo docker version
Client: Docker Engine - Community
 Version:           23.0.2
 API version:       1.42
 Go version:        go1.19.7
 Git commit:        569dd73
 Built:             Mon Mar 27 16:16:18 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          23.0.2
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.19.7
  Git commit:       219f21b
  Built:            Mon Mar 27 16:16:18 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.19
  GitCommit:        1e1ea6e986c6c86565bc33d52e34b81b3e2bc71f
 runc:
  Version:          1.1.4
  GitCommit:        v1.1.4-0-g5fd4c4d
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Install gitlab-runner

次に https://docs.gitlab.com/runner/install/linux-repository.html#installing-gitlab-runner に沿ってGitlab runnerをインストールします。

curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install -y gitlab-runner

Gitlab runnerのVersionは以下の通りです。

$ gitlab-runner -v
Version:      15.10.0
Git revision: 456e3482
Git branch:   15-10-stable
GO version:   go1.19.6
Built:        2023-03-17T13:42:46+0000
OS/Arch:      linux/amd64

Register gitlab-runner as Project runner

このGitlab runnerは、今回作成したプロジェクト専用のRunnerとして登録します。
先ほど確認したプロジェクト専用のregistration tokenを --registration-token オプションで指定します。

export GITLAB_PROJECT_TOKEN="GR1348941Kjym6XqzXhGzfczuoSNB"
sudo -E gitlab-runner register --non-interactive \
   --url http://qiita-gitlab.example.com \
   --registration-token $GITLAB_PROJECT_TOKEN \
   --description "Qiita example" \
   --tag-list "docker,qiita" \
   --executor docker \
   --docker-image alpine:latest
  • --executordocker を選択した場合は、デフォルトで使用されるコンテナを合わせて指定します。特に使う予定は無いので適当に alpine:latest を設定しました。
  • --tag-list は指定しなくても構いませんが、CI実行時にタグによって実行Runnerを使い分けることが出来るので、参考に付与しています。

以下のように、登録に成功したログが出ていればOKです。

Registering runner... succeeded                     runner=GR1348941Kjym6Xqz
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
 
Configuration (with the authentication token) was saved in "/etc/gitlab-runner/config.toml" 

GitlabのWeb UIでも、Gitlab runnerが登録されていることが確認できます。

image.png

Add sample files to gitlab project

それでは、今回作成したプロジェクトに、サンプルコードを登録しましょう。
Gitlab-CIの動作を見るため、以下の2つのファイルを作成します。

  • Dockerfile: 自動ビルドしたいサンプルコンテナ
  • index.html: 適当な文字列を表示するHTMLファイル

Dockerfile

FROM nginx:latest

COPY index.html /usr/share/nginx/html/index.html

index.html

<!DOCTYPE html><meta charset=utf-8>
<title>Hello world</title>
<body>Gitlab-CI<body>

gitコマンドを使っても良いのですが、今回はWebから全部やりましょう。
リポジトリのページから New file を選択して、上記のファイルを2つ登録します。

image.png

Webエディタが起動するので、新しいファイルを作成して内容を記入します。

image.png

できたらCommitします。

image.png

Setup Gitlab container registry

更に、今回ビルドしたコンテナを保存する先を作成します。
Gitlabには GitLab Container Registry 機能があるので、コンテナイメージをホスティングできるのです。

今回は自分で作成したCAと証明書を使って Configure Container Registry under its own domain に沿って設定します。
作業は qiita-gitlab ノードで実施します。

Let’s Encryptなど正規の証明書が取得できる場合は読み飛ばしてください。
また、証明書周りの説明はGitlab CIの本筋から少しずれるため、コマンドを貼り付けるのみでサッと進めます。

Create CA

まずはCAを作成します。国や都市名は適当です。
CNはこの後作成する証明書に合わせて example.com にします。

$ mkdir registry_certs
$ cd registry_certs/
$ openssl rand -writerand ~/.rnd
$ openssl genrsa -out ca.key 4096
$ openssl req -x509 -new -nodes -sha512 -days 3650 \
   -subj "/C=JP/ST=tokyo/L=example/O=gitlab/CN=example.com" \
   -key ca.key -out ca.crt

Create self-signed certification

作成したCAを元にコンテナレジストリ用の証明書を作成します。
FQDNはGitlabのデフォルトに合わせて registry.example.com にします。

$ openssl genrsa -out registry.example.com.key 4096
$ openssl req -sha512 -new \
    -subj "/C=JP/ST=SDI/L=lab/O=SDI/CN=registry.example.com" \
    -key registry.example.com.key -out registry.example.com.csr
$ cat <<_EOL_ > v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1=registry.example.com
DNS.2=registry
DNS.3=gitlab
_EOL_
$ openssl x509 -req -sha512 -days 3650 -extfile v3.ext \
    -CA ca.crt -CAkey ca.key -CAcreateserial \
    -in registry.example.com.csr -out registry.example.com.crt

Enable Gitlab container registry

最後に、作成したCAと証明書をGitlabの設定ディレクトリに格納して、コンテナレジストリ機能を有効にします。

$ sudo cp ca.crt /etc/gitlab/trusted-certs/
$ sudo mkdir /etc/gitlab/ssl
$ sudo cp registry.example.com.crt /etc/gitlab/ssl/
$ sudo cp registry.example.com.key /etc/gitlab/ssl/
$ sudo sed -i -e "s|# registry_external_url 'https://registry.example.com'|registry_external_url 'https://registry.example.com'|" /etc/gitlab/gitlab.rb
$ sudo gitlab-ctl reconfigure

設定が完了すると /opt/gitlab/embedded/ssl/certs にCAのシンボリックリンクが作成されます。

$ ls -l /opt/gitlab/embedded/ssl/certs
total 224
lrwxrwxrwx 1 root root     32 Mar 28 13:03 5a842aa3.0 -> /etc/gitlab/trusted-certs/ca.crt
-rw-r--r-- 1 root root    147 Mar 28 12:04 README
-rw-r--r-- 1 root root 224369 Mar 21 10:30 cacert.pem

Setting Gitlab runner host to use seif-signed ceritication

Gitlab runnerにも ca.crt を(SFTPなどで)コピーして、CAを登録しておきます。
CAの登録コマンドは、Ubuntuの場合は以下のようになります。

$ sudo cp ca.crt /usr/local/share/ca-certificates/registry.example.com.crt
$ sudo update-ca-certificates
$ sudo systemctl restart docker

また、Gitlab runnerのコンテナ内部からはgitリポジトリなる qiita-gitlab.example.com とコンテナレジストリとなる registry.example.com にアクセスできる必要があります。
一般的にはDNSで解決すべきものですが、ここでは手順通りの設定で動くように /etc/gitlab-runner/config.tomlextra_hosts の設定を加えておきましょう。

--- config.toml.old     2023-03-28 13:40:40.111871790 +0000
+++ config.toml 2023-03-28 13:40:09.031921214 +0000
@@ -24,3 +24,4 @@
     disable_cache = false
     volumes = ["/cache"]
     shm_size = 0
+    extra_hosts = ["qiita-gitlab.example.com:192.168.122.246","registry.example.com:192.168.122.246"]

設定を変更したら sudo gitlab-runner restart で再起動して、設定を適用します。

Create .gitlab-ci.yml

Start gitlab pipelines

まだ何もGitlab CIの設定を入れていないので、作成画面から作業を始めます。

CI/CD -> pipeline -> Editor を開きます。

image.png

"Configure pipelines" を選択します。

image.png

デフォルトの設定が書かれた .gitlab-ci.yml の入力画面が表示されるので、内容を決めていきましょう。

Edit .gitlan-ci.yml to use kaniko

それでは、いよいよKanikoを使用してコンテナをビルドするための .gitlab-ci.yml を作成します。
今回はサンプルで作成したDockerfileを使って、自前のコンテナを自動ビルドするように設定します。

KanikoはDockerfileを読み込むものの、Gitlab runnerがDockerの特権を持たなくてもコンテナのビルドが出来るため、比較的安全かつDocker buildによるゴミが残りにくいという利点があります。

.gitlab-ci.yml の作成にあたっては、GitlabがKanikoを利用する場合の文書 Use kaniko to build Docker images を参考にします。

まずは Building a Docker image with kaniko に書かれているサンプルを丸ごとそのままコピーします。

ただ、それだけでは少し不足があるので2点ほど追記します。

  • 登録したGitlab runnerには docker というタグを付けてあるので、それを先頭に付与します
    • 動作上は必須ではありませんが、今回登録したRunnerをタグで明示しておくと、Gitlab runnerが複数存在する時に区別しやすくなります
  • Gitlab runnerがコンテナレジストリの証明書エラーとならないよう $REGISTRY_CERT (※登録方法は後述)をkanikoコンテナの中に設置します
    • Using a registry with a custom certificate を見ると /kaniko/ssl/certs/additional-ca-cert-bundle.crt にCAを追加する手順が記載されていますが、そのままだと .gitlab-ci.yml が長くなってしまうので変数に置き換えています
default:
  tags:
    - docker

build:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:v1.9.0-debug
    entrypoint: [""]
  script:
    - echo "$REGISTRY_CERT" >> /kaniko/ssl/certs/additional-ca-cert-bundle.crt
    - /kaniko/executor
      --context "${CI_PROJECT_DIR}"
      --dockerfile "${CI_PROJECT_DIR}/Dockerfile"
      --destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}"
  rules:
    - if: $CI_COMMIT_TAG

あとは "Commit changes" で確定して、mainブランチに .gitlab-ci.yml を追加しましょう。
if: $CI_COMMIT_TAG と記述しているので、コミットにタグを付けるとCIが起動するようになりました。

kanikoコンテナの指定に -debug が付与されていることを奇妙に思うかもしれませんが、GitlabではCI/CDの動作にシェルが必要になるため、これを外すと動作しなくなる可能性があります。

The kaniko debug image is recommended (gcr.io/kaniko-project/executor:debug) because it has a shell, and a shell is required for an image to be used with GitLab CI/CD.
Building a Docker image with kaniko

Docs feedback: Building a Docker image with kaniko: debug image required?

Add REGISTRY_CERT variable

先ほど設定した REGISTRY_CERT は、今のままでは空っぽなので Settings -> CI/CD -> Variables から、作成した ca.crt の内容をCIの変数で展開できるようにしておきます。

image.png

参考にした Using a registry with a custom certificate の記述では .gitlab-ci.yml に直接記載していましたが、今回はVariablesを使用しました。

Gitlabで使う共通のコンテナレジストリ用のCAなので、Gitlab全体(Adminコントロールパネル)のVariableに設定しても良いでしょう。

設定すると、下図のようになります。

image.png

CAをkanikoが参照できるように設定できていないと、以下のようなエラーが出ます。

error checking push permissions -- make sure you entered the correct tag name, and that you are authenticated correctly, and try again: checking push permission for "registry.example.com/gitlab-instance-6dfd6d5f/gitlab-ci-sample:sample": creating push check transport for registry.example.com failed: Get "https://registry.example.com/v2/": x509: certificate signed by unknown authority

Check results

Gitlab pipeline

まずはコミットにTagを付けてみましょう。

image.png

適当なタグを設定します。

image.png

Tagを付けると、それに連動してPipelineが起動しました。

image.png

Passedになったので、ジョブ結果を見てみます。

image.png

以下のようなログが確認できたので、コンテナレジストリへの登録が成功しているようです。

INFO[0009] Pushing image to registry.example.com/gitlab-instance-6dfd6d5f/gitlab-ci-sample:sample

Gitlab container registry

早速 Packages and registries -> Container Registry を見に行くと、コンテナが登録されていました。

image.png

中には、設定したタグのコンテナが登録されています。

image.png

やりました!コンテナの自動ビルド達成です。

Use Gitlab container registry

では、コンテナレジストリからコンテナを取得して実行してみましょう。
Gitlab runnerにはDockerをインストール済みなので、そこで実行してみます。
ログインに使用するアカウントは root のものを使用します。

$ sudo -i
# docker login registry.example.com
Username: root
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
# docker pull registry.example.com/gitlab-instance-6dfd6d5f/gitlab-ci-sample:sample
sample: Pulling from gitlab-instance-6dfd6d5f/gitlab-ci-sample
f1f26f570256: Already exists 
84181e80d10e: Already exists 
1ff0f94a8007: Already exists 
d776269cad10: Already exists 
e9427fcfa864: Already exists 
d4ceccbfc269: Already exists 
18059bb02c01: Pull complete 
Digest: sha256:6be901ad0d7b7a7b6720bd9a5dcd333bd5d60f977c58481ea7d01d5f42be1359
Status: Downloaded newer image for registry.example.com/gitlab-instance-6dfd6d5f/gitlab-ci-sample:sample
registry.example.com/gitlab-instance-6dfd6d5f/gitlab-ci-sample:sample

なお registry.example.com は例示用のURLですが、アクセスできないと docker login に失敗するのでhostsファイルに追記しています。(手順外)

無事に取得できたようです。
作成したコンテナは単なるnginxに静的HTMLファイルを置いただけなので、8000/TCPで動かしてみましょう。

# docker run --rm --name sample -p 8000:80 -d registry.example.com/gitlab-instance-6dfd6d5f/gitlab-ci-sample:sample
ad1f2438b8ae3e90e487d73b0d6c2d5982cb6200971cea596f8a08e129711403
# curl localhost:8000
<!DOCTYPE html><meta charset=utf-8>
<title>Hello world</title>
<body>Gitlab-CI<body>

Gitlab CIとkanikoを使用して、コンテナの自動ビルドとコンテナの配布環境が整いました。

Closing...

Gitlabの構築からコンテナの自動ビルド設定、Gitlabのコンテナレジストリを使ったコンテナの配布環境作成までの道のりを駆け足で辿ってみました。
Gitlabはインストールやアップデートが比較的容易で、無償の範囲でも多くの使い方ができるので、是非活用したいアプリケーションです。

今回は外部環境の依存を避けるために少々寄り道と言いますか、注釈が多くなってしまいました。
やはり、出来るだけDNSや証明書の準備が容易な環境で構成したいですね。

近頃ではGithub actionsが強いので組織内にGitlabを置きたいという話も徐々に減っていると思いますが、上手く棲み分けできると良いのかなと思います。

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3