Jenkinsを使って色々なプロダクトのビルドをするようになってくると、プロダクト間でのライブラリやツールのバージョン競合が増えてきます。また、ビルド用のツールをJenkinsに設定するため、Jenkins設定の管理も必要になるのでこれも手間です。そこで、できるだけビルド設定は各プロダクト内で管理したい、Jenkinsへの依存は減らしたいと思ったのでビルド環境をDockerで作成し、JenkinsJobはJenkinsfileで設定するようにしました。
やること
- Dockerイメージを管理するPrivateRegistryの構築
- ビルド用Dockerイメージの作成
- ビルド処理をJenkinsfileで設定
これから3回に分けて書いていきたいと思います。
1. Dockerイメージを管理するPrivateRegistryの構築
JenkinsJobを処理する環境に手動でビルド用のDockerイメージを作成するのは手間なので、docker pullできるようにするためPrivateDockerRepogistryを作成します。
社内ではGitLabを使っていて、GitLabにはDockerRegistryも入っているので、今回はこれを利用します。
社内のGitLabはDockerで動いており、そのイメージはsameersbn/docker-gitlabを使わせてもらっています。READMEに従ってGitLab Container Registryの設定を行います。
サーバー証明書の準備
DockerRegistryを使うためにはHTTPSによる通信が必要になります。そこでサーバー証明書が必要になりますが、今回は自己証明書で対応します。(自己証明書だと利用する側への設定(後述)も必要になるので管理面でもセキュリティ面でもちゃんとした証明書を利用したほうがいいです)
DockerRegistryを構築するホスト名をgitlab.example.com
とした場合、以下のコマンドで証明書を作成します。
$ openssl req -nodes -newkey rsa:4096 -keyout gitlab.exapmle.com-auth.key -out gitlab.exapmle.com-auth.csr -subj "/CN=gitlab.example.com"
$ openssl x509 -in gitlab.example.com-auth.csr -out gitlab.example.com-auth.crt -req -signkey gitlab.example.com-auth.key -days 3650
これで、gitlab.example.com-auth.key
, gitlab.example.com-auth.csr
, gitlab.example.com-auth.crt
の3つが作成されます。このうち.key
,.crt
の2つを利用します。
次に、DockerRegistryに接続する側に先ほど作成したサーバー証明書を登録します。信頼された証明機関から発行された証明書を利用する場合は、この作業は不要です。
接続する側がLinuxの場合、先ほど作成したgitlab.example.com-auth.crt
ファイルを/etc/docker/certs.d/gitlab.example.com:5000/ca.crt
として配置します。配置先のディレクトリ名のgitlab.example.com:5000
はDockerRegistryが稼働しているサーバーのホスト名、ポート番号になります。
Linux以外の場合など詳しくは、docker docs(DockerRegistry)を参照してください。
DockerRegistryコンテナの設定
GitLabからDockerRegistryを利用できるようにするため、GitLabのdocker-compose.ymlの設定を変更します。
まずは、GitLabコンテナの設定変更です。
gitlab:
・・・
volumes:
- /opt/docker/gitlab/certs:/certs
・・・
external_links:
- "registry:gitlab.example.com"
environment:
- GITLAB_REGISTRY_ENABLED=true
- GITLAB_REGISTRY_HOST=gitlab.example.com
- GITLAB_REGISTRY_PORT=5000
- GITLAB_REGISTRY_API_URL=https://gitlab.example.com:5000
- GITLAB_REGISTRY_CERT_PATH=/certs/gitlab.example.com-auth.crt
- GITLAB_REGISTRY_KEY_PATH=/certs/gitlab.example.com-auth.key
・・・
サーバー証明書はGitLabコンテナとDockerRegistryコンテナの両方で参照するので、ホスト上(/opt/docker/gitlab/certs)に配置して共有するようにしています(volumesの設定)。また、gitlabコンテナ内からregistryコンテナへgitlab.example.com
という名前でアクセスできるようにするため、external_linksを設定しています。公式ドキュメントにはexternal_linksの設定はなく、GITLAB_REGISTRY_API_URL
の設定はhttp://registry:5000
とコンテナ名でアクセスするようになっていましたが、この通りやるとサーバー証明書のチェックに失敗して接続ができなかったのでexternal_linksを使うようにしています。別の原因で接続できなかっただけかもしれないので、何か知っている人がいたら教えて欲しいです。
次は、DockerRegistryコンテナの設定追加です。
registry:
image: registry:2.4.1
ports:
- "5000:5000"
volumes:
- registry-data:/var/lib/registry
- /opt/docker/gitlab/certs:/certs
environment:
- REGISTRY_LOG_LEVEL=info
- REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry
- REGISTRY_AUTH_TOKEN_REALM=http://gitlab.example.com/jwt/auth
- REGISTRY_AUTH_TOKEN_SERVICE=container_registry
- REGISTRY_AUTH_TOKEN_ISSUER=gitlab-issuer
- REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/gitlab.example.com-auth.crt
- REGISTRY_STORAGE_DELETE_ENABLED=true
- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/gitlab.example.com-auth.crt
- REGISTRY_HTTP_TLS_KEY=/certs/gitlab.example.com-auth.key
- REGISTRY_HTTP_SECRET=secret
こちらもgitlabコンテナと同様にホスト上のサーバー証明書を参照するためvolumes設定しています。
これで、GitLabからDockerRegistryが利用できるようになります。GitLabのプロジェクトごとにRegistryを利用するかどうか設定ができますので、プロジェクトのSettings
ページよりContainer Registry
機能を有効にしてください。
Dockerイメージを登録できるようになったので、次回はJenkinsJobで利用するコンテナの作成をします。
参考までにGitLabを動かすためのdocker-compose.ymlの全体も書いておきます(ホスト名やセキュリティに関するところはマスクしてます)。
version: '2'
services:
gitlab-redis:
image: sameersbn/redis:latest
volumes:
- /etc/localtime:/etc/localtime:ro
networks:
- proxy_network
gitlab-postgresql:
image: sameersbn/postgresql:9.5-1
ports:
- "15432:5432"
environment:
- DB_NAME=gitlabhq_production
- DB_USER=xxxxxx
- DB_PASS=xxxxxx
- DB_EXTENSION=pg_trgm
volumes:
- /opt/docker/gitlab/postgresql/data:/var/lib/postgresql
- /etc/localtime:/etc/localtime:ro
networks:
- proxy_network
gitlab:
image: sameersbn/gitlab:9.3.5
depends_on:
- gitlab-redis
- gitlab-postgresql
ports:
- "10080:80"
- "10022:22"
volumes:
- /opt/docker/gitlab/git:/home/git/data
- /opt/docker/gitlab/logs:/var/log/gitlab
- /opt/docker/gitlab/certs:/certs
- /etc/localtime:/etc/localtime:ro
external_links:
- "registry:gitlab.example.com"
environment:
- DB_ADAPTER=postgresql
- DB_HOST=gitlab-postgresql
- DB_PORT=5432
- DB_USER=xxxxxx
- DB_PASS=xxxxxx
- DB_NAME=gitlabhq_production
- REDIS_HOST=gitlab-redis
- REDIS_PORT=6379
- GITLAB_TIMEZONE=Tokyo
- GITLAB_PORT=10080
- GITLAB_HOST=gitlab.example.com
- GITLAB_RELATIVE_URL_ROOT=/gitlab
- GITLAB_SHELL_SSH_PORT=10022
- GITLAB_EMAIL=xxxx@xxxxxxx.com
- GITLAB_EMAIL_DISPLAY_NAME=GitLab
- GITLAB_BACKUP_SCHEDULE=daily
- GITLAB_BACKUP_TIME=01:00
- GITLAB_BACKUP_EXPIRY=86400
- GITLAB_SECRETS_DB_KEY_BASE=xxxxxxxxxxxxxxxxxxxxxx
- GITLAB_SECRETS_SECRET_KEY_BASE=xxxxxxxxxxxxxxxxxxxxxx
- GITLAB_SECRETS_OTP_KEY_BASE=xxxxxxxxxxxxxxxxxxxxxx
- GITLAB_REGISTRY_ENABLED=true
- GITLAB_REGISTRY_HOST=gitlab.example.com
- GITLAB_REGISTRY_PORT=5000
- GITLAB_REGISTRY_API_URL=https://gitlab.example.com:5000
- GITLAB_REGISTRY_CERT_PATH=/certs/gitlab.example.com-auth.crt
- GITLAB_REGISTRY_KEY_PATH=/certs/gitlab.example.com-auth.key
- SMTP_DOMAIN=xxxxxxxxxx
- SMTP_HOST=xxxxxxxxxx
- SMTP_PORT=25
- SMTP_USER=xxxxxxxx
- SMTP_PASS=xxxxxxxx
- UNICORN_TIMEOUT=300
networks:
- proxy_network
registry:
image: registry:2.4.1
ports:
- "5000:5000"
volumes:
- registry-data:/var/lib/registry
- /etc/localtime:/etc/localtime:ro
- /opt/docker/gitlab/certs:/certs
environment:
- REGISTRY_LOG_LEVEL=info
- REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry
- REGISTRY_AUTH_TOKEN_REALM=http://gitlab.example.com:10080/gitlab/jwt/auth
- REGISTRY_AUTH_TOKEN_SERVICE=container_registry
- REGISTRY_AUTH_TOKEN_ISSUER=gitlab-issuer
- REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/gitlab.example.com-auth.crt
- REGISTRY_STORAGE_DELETE_ENABLED=true
- REGISTRY_HTTP_TLS_CERTIFICATE=/certs/gitlab.example.com-auth.crt
- REGISTRY_HTTP_TLS_KEY=/certs/gitlab.example.com-auth.key
- REGISTRY_HTTP_SECRET=secret
networks:
- proxy_network
volumes:
registry-data:
networks:
proxy_network:
external: true