WSL + DockerでGitLab環境構築
はじめに
今回、ローカル(WSL上)でGitLabを起動し、Git、Container Repository、CI/CDでのビルド、デプロイ(ssh経由)を行う手順を公開しました。今後、社内でGitLabの導入を検討されている方の参考資料として、活用いただければ幸いです。
ただし、一般的に公開されている手順とは異なり、ビルド・デプロイを高速化した手順となっていますので、ご注意ください。また、メモリをOS含めて12Gほど消費するため、専用PCにセットアップしたほうが快適に利用できます。
GitLab
GitLabとは、Gitリポジトリ機能を中心としたDevOpsのオールインワンパッケージソフトです。具体的には、Gitリポジトリ以外に、Package/Container Repository, Redmine, Backlog, Jenkins, WikiなどがGitLab上で利用でき、使いこなせば最強ツールになります。しかも、core機能はOSSとして無料で使用でき、有料サポートでも1ユーザ$19/月~で利用できます。
Dockerでのインストール
サーバとして起動する場合は、IPアドレスをルータで固定化することをお勧めします。Dockerのインストール手順および使い方は、前の記事を参考にしてください。
- 公式ページを参考に、Dockerでインストールを行う。
GITLAB_HOME=/srv/gitlab
GITLAB_URL=gitlab.example.com
version: "3.6"
services:
web:
image: 'gitlab/gitlab-ee:latest'
restart: always
hostname: '$GITLAB_URL'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://$GITLAB_URL'
registry_external_url 'https://$GITLAB_URL:4567'
nginx['ssl_certificate'] = "/etc/gitlab/ssl/$GITLAB_URL.crt"
nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/$GITLAB_URL.key"
ports:
- '443:443'
- '4567:4567'
volumes:
- '$GITLAB_HOME/config:/etc/gitlab'
- '$GITLAB_HOME/logs:/var/log/gitlab'
- '$GITLAB_HOME/data:/var/opt/gitlab'
- デフォルトでは、gitlab.example.comのSSL証明書(30日分)が自動生成される。ドメイン名は、SSL証明書の再作成時に変更可能。
- Container RepositoryがデフォルトOFFなので、有効にする。
- OS起動時に毎回サービスを起動させたくない場合は、restart: alwaysを削除する。
- docker-composeでサービスを起動してみる。
$ docker-compose up -d
- 以下のURLでログイン画面が表示されるか確認する。この時点ではURLが異なるのと、証明書をブラウザにインポートしていないため、警告が出る。
https://localhost/
ドメインおよびSSL設定
ドメイン設定は、本来はDNSで行うが、今回はローカル環境なので/etc/hostsで行う。また、SSL証明書が30日しか利用できないので、新しいファイルに差し替える。
- Port Proxyおよびパーソナルファイアウォールの開放で、他のPCからPORT 22,443,4567でアクセスできるようにする。
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit }
# ip address
$oldaddr = "192.168.1.XXX"
$newipaddr = "192.168.1.XXX"
# portproxy
netsh interface portproxy delete v4tov4 listenport=4567 listenaddress=$oldipaddr
netsh interface portproxy delete v4tov4 listenport=443 listenaddress=$oldipaddr
netsh interface portproxy delete v4tov4 listenport=22 listenaddress=$oldipaddr
netsh interface portproxy add v4tov4 listenport=4567 listenaddress=$newipaddr connectport=4567 connectaddress=127.0.0.1
netsh interface portproxy add v4tov4 listenport=443 listenaddress=$newipaddr connectport=443 connectaddress=127.0.0.1
netsh interface portproxy add v4tov4 listenport=22 listenaddress=$newipaddr connectport=443 connectaddress=127.0.0.1
netsh interface portproxy show all
# firewall
netsh advfirewall firewall delete rule name=gitlab
netsh advfirewall firewall add rule name=gitlab dir=in action=allow protocol=TCP localport=22,443,4567
netsh advfirewall firewall show rule name=gitlab
pause -1
- ドメイン設定を行う。Windowsキー+Rでdriversを実行し、etc/hostsにドメイン名を追加する。VS Codeを利用すると、管理者権限で保存できる。
192.168.1.XXX gitlab.example.com
- gitlabのコンテナ内で、既存の秘密鍵を利用し、有効期限10年のSSL証明書を再作成する。
$ cd /etc/gitlab/ssl
$ mv gitlab.example.com.crt gitlab.example.com.crt.bk
→ 既存のCRTファイルをバックアップ
→ 秘密鍵の再作成(openssl genrsa 2048 > gitlab.example.com.key)は省略
$ openssl req -new -key gitlab.example.com.key -subj "/CN=gitlab.example.com" > gitlab.example.com.csr
→ 秘密鍵から公開鍵(csrファイル)を作成。subjectはCNのみ。
$ echo "subjectAltName = DNS:gitlab.example.com" > san.txt
→ ChromeではCNではなく、SAN(Subject Alternative Name)を読み込むので作成。
$ openssl x509 -days 3650 -in gitlab.example.com.csr -out gitlab.example.com.crt -req -signkey gitlab.example.com.key -extfile san.txt
→ オレオレ証明書(crtファイル)を作成する。
- コンテナ内で作成したcrtファイルを、WSL上にコピーする。
$ cd ~/gitlab
$ docker cp gitlab_web_1:/etc/gitlab/ssl/gitlab.example.com.crt .
- VS Codeのエクスプローラにてcrtファイルをダウンロードし、以下のパス経由でcrtファイルを参照し、「信頼されたルート証明機関」で証明書をインストールする。
- Edgeの場合:ダブルクリック
- Chromeの場合:[設定]-[プライバシーとセキュリティ]-[セキュリティ]-[証明書の管理]
- Firefoxの場合:[設定]-[プライバシーとセキュリティ]-[セキュリティ]-[証明書を表示]
- コンテナを再起動し、以下のURLで正常にログイン画面が表示されるか確認する。
https://gitlab.example.com/
初期設定
- rootパスワードを初期化する。docker版だとパスワード変更画面が出てこないので、コンテナ内でパスワード変更を行う。起動まで時間がかかる。
$ gitlab-rails console -e production
irb(main):001:0>
user = User.where(id: 1).first
user.password = 'password'
user.password_confirmation = 'password'
user.save!
exit
- rootユーザでログインする。日本語化はPreferences - Localization、パスワード変更はEdit Profile - Passwordで行う。
- ユーザを作成する。左上のMenu - Admin - Users - New userを選択。
・Name, Username, Emailを指定する。
・その際、パスワードがランダム生成されるため再度編集し、パスワードを変更する。※メール設定を行えば、パスワードがメールで届くが、今回は省略。 - 作成したユーザで、Docker経由でContainer Repositoryにログインしてみる。ログインする前にCSRファイルをDockerにコピーする必要がある。
$ docker login gitlab.example.com:4567
Login did not succeed, error: Error response from daemon: Get "https://gitlab.example.com/v2/": x509: certificate signed by unknown authority
→ 不明な機関ということでエラーになるため、オレオレ証明書をdockerにインストールする。
$ sudo mkdir -p /etc/docker/certs.d/gitlab.example.com:4567
$ sudo cp ~/gitlab/gitlab.example.com.crt /etc/docker/certs.d/gitlab.example.com:4567/ca.crt
→ SSL設定で利用したCSRファイルを、Dockerの証明書フォルダにコピーする。
$ docker login gitlab.example.com:4567
Username: <UserID>
Password: <Password>
WARNING! Your password will be stored unencrypted in /home/atoji/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
→ ログインができるようになる。2回目以降はパスワード不要。警告メッセージは、Dockerの標準仕様。
GitLab Runner
GitLab Runnerは、CI/CDをリモートサーバで実行できるようにするツールです。
公式で推奨されているのは、Docker方式ですが、毎回パッケージがダウンロードされてしまい、ビルドが少し遅いため、shellで動かす手順にしています。Dockerでも、.gitlab-ci.ymlにcacheを指定する(記載例あり)と、毎回ダウンロードされることはないので、どちらでも構いません。
また、Runnerには、専用(Specific runners)と共有(Shared runners)の2種類が存在しますが、今回はShared runnersを利用しています。
GitLab Runnerイメージ作成
今回は、shellで実行するため、GitLab Runnerに必要なパッケージをインストールします。今回は、jdkとnpmを入れてみました。
- 作成したユーザでログインし、グループを作成(Create a group - Create group)する。
・Group name, Group URL : traning - GitLab Runner用のプロジェクトを作成(New project - Create blank project)する。
・Project name, Project slug : gitlab-runner
・Initialize repository with a README : チェックを外す
※初回git利用時のみ
$ git config --global user.name "<ユーザ名>"
$ git config --global user.email "<メールアドレス>"
$ git config --global http.sslVerify false
→ オレオレ証明書を利用できるようにする。
$ git config --global credential.helper store
→ ログイン・パスワードを保存する。
$ git clone https://gitlab.example.com/training/gitlab-runner.git
→ 外部公開するときは、GitHubと同じように、2段階認証に変更し、SSHでログインしたほうがよい。
やり方はGitHubと同じなので割愛する。
- GitLab Runnerでjdk 17およびnpm 8.3.0が利用できるように、Dockerfileを作成する。
FROM gitlab/gitlab-runner:ubuntu
# jdk 17
RUN apt-get -y update
RUN apt-get install -y openjdk-17-jdk
# npm
RUN apt-get install -y curl gnupg
RUN curl -fsSL https://deb.nodesource.com/setup_17.x | bash -
RUN apt-get install -y nodejs
RUN npm install npm@latest -g
→ packege.jsonやbuild.gradleを用意すれば、事前にパッケージもイメージ化できる。
- Dockerイメージをビルドし、Container Repositoryにpushする。
$ docker image build -t gitlab.example.com:4567/training/gitlab-runner .
$ docker push gitlab.example.com:4567/training/gitlab-runner
GitLab Runner実行・登録
- 作成したDockerイメージをもとに、docker-composeを作成する。また、gitlabで作成したオレオレ証明書も同フォルダにコピーする。
version: '3.6'
services:
runner:
image: 'gitlab.example.com:4567/training/gitlab-runner'
tty: true
container_name: gitlab-runner
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /srv/gitlab-runner/config:/etc/gitlab-runner
- ~/gitlab-runner/certs:/etc/gitlab-runner/certs
$ mkdir certs
$ cp ~/gitlab/gitlab.example.com.crt certs/
- 作成したファイルはgitでpushしておき、GitLab Runnerを起動する。
$ docker-compose up -d
- GitLabにrootでログインし、Menu - Admin - Overview - Runnersを選択し、[Register an instance runner]でtokenを取得する。
- Runnerのコンテナ上で、以下のコマンドを実行し、Runnersが追加されたことを確認する。
$ gitlab-runner register
Enter the GitLab instance URL : https://gitlab.example.com/
Enter the registration token: <token>
Enter a description for the runner: ⏎(任意の名前を設定できる)
Enter tags for the runner (comma-separated): ⏎(タグが設定できる)
Enter an executor: shell (dockerでもOK, Docker imageはなんでもよい)
(コマンドで登録する場合)
$ gitlab-runner register -n --url https://gitlab.example.com/ --registration-token <token> --executor shell
別サーバでのGitLab Runner
ここでは、別サーバでGitLab Runnerを動かすための手順を記載しています。PCが1台しかない場合は、本手順はスキップしてください。
- WSL上で、Dockerをインストールする。
- ドメインおよびSSL設定の2,5を実施し、https://gitlab.example.com/ にログインできるようにする。
- 初期設定の5を実施し、Container Repositoryに接続できるようにする。
- 先ほど作成したdocker-composeをgitから取得する。
$ git clone https://gitlab.example.com/training/gitlab-runner.git
- あとは、GitLab Runner実行・登録の2~4を実施すると、他のサーバでもGitLab Runnerが利用可能となる。
ビルド・デプロイ
前回作成したJavaのHello WorldをGitLabにコミットし、CI/CDでビルド・デプロイを行います。
Hello Worldプロジェクト作成・ビルド
- プロジェクトを作成(New project - Create blank project)する。
・Project name, Project slug : hello-world
・Initialize repository with a README : チェックを外す(gitのコマンドサンプルが表示される)
$ git clone https://gitlab.example.com/training/hello-world.git
- 前回、java17で作成したhello-worldをコピーし、コミットを行う。
- 自動ビルドができるように、CIパイプライン(.gitlab-ci.yml)を作成する。gitでpushを行うと、パイプラインが自動実行される。
stages:
- build
build:
stage: build
# runnerをdockerにした場合は、コメント部分を外す
#image: openjdk:17-alpine
#cache:
# key: ${CI_COMMIT_REF_SLUG}
# paths:
# - .gradle/
script:
- ./gradlew build -x test
artifacts:
paths:
- build/libs
- GitLab上で、CI/CD - Pipelinesを確認し、実行結果を確認する。Retryで再実行できる。
※私のPCでは、1回目が1分6秒、2回目以降は3秒でした。
Javaアプリ用Dockerイメージ作成
通常、その後はdockerイメージをビルドし、コンテナレジストリに登録するのが一般的ですが、今回は、Javaアプリ用のDockerイメージを作成し、そのイメージのjarファイルを差し替える方法を紹介します。これにより、デプロイ時のイメージビルドが不要になるため、デプロイが早くなります。
- javaアプリ用のプロジェクトを作成する。
・Project name, Project slug : java-app
・Initialize repository with a README : 外す。
$ git clone https://gitlab.example.com/training/java-app.git
- javaアプリ用のDockerイメージを作成する。
FROM openjdk:17-alpine
RUN addgroup -S spring && adduser -S spring -G spring
ENV TZ=Asia/Tokyo
USER spring:spring
COPY app/app.jar /app/app.jar
ENTRYPOINT java -jar /app/app.jar
- 今回作成したHello Worldのjarファイルを、app/app.jarとして保存し、pushしておく。
- Dockerイメージをビルドし、Container Repositoryにpushする。
$ docker image build -t gitlab.example.com:4567/training/java-app .
$ docker push gitlab.example.com:4567/training/java-app
- テストとして、Dockerコンテナを起動し、WEB画面が表示されるか確認する。
http://localhost:8080/
docker run -d -p 8080:8080 gitlab.example.com:4567/training/java-app
sshでのデプロイ
作成したjavaアプリ用Dockerイメージを利用し、CIパイプラインで指定したサーバにデプロイを行います。
- デプロイする端末で、sshを利用できるようにsshdを起動する。
$ sudo service ssh start
自動起動にしたい場合は、dockerと同じように.bashrcに追加する。
echo "" >> ~/.bashrc
echo "if [ \$(service ssh status | awk '{print \$4}') = \"not\" ]; then" >> ~/.bashrc
echo " sudo service ssh start > /dev/null" >> ~/.bashrc
echo "fi" >> ~/.bashrc
- サーバで秘密鍵(id_rsa)と公開鍵(id_rsa.pub)を作成し、公開鍵のファイル名を変更する。
$ ssh-keygen -t rsa
→ 3回リターンを押すと、~/.sshに鍵が作成される。
$ cd ~/.ssh
$ mv id_rsa.pub authorized_keys
- 秘密鍵をGitLabのhello-worldプロジェクトに登録(Settings - CI/CD - Variables)する。
・Type : Variable(デフォルトのまま)
・Key : SSH_PRIVATE_KEY
・Value : ~/.ssh/id_rsaの内容 - CIパイプライン(.gitlab-ci.yml)に、deploy stagingを追加する。docker版の場合、デプロイ用のimageを作ったほうがよい。
image: ubuntu:20.04
stages:
- build
- deploy staging
variables:
USERID: <ユーザID>
STAGING_HOSTNAME: gitlab.example.com
STAGING_PORT: 8080
STAGING_CONTAINER_NAME: hello-staging
STAGING_DOMAIN: http://localhost:8080/
build:
stage: build
script:
- ./gradlew build -x test
artifacts:
paths:
- build/libs
# デプロイ用テンプレート
.deploy_template: &deploy
#image: ubuntu:20.04
variables:
# チェックアウトしない。
GIT_STRATEGY: none
before_script:
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
# 新規ホストの確認を不要にする。
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
# 秘密鍵をファイル保存する。
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
#- apt-get update -y & apt-get install openssh-client -y
script:
# jarファイルをコピーする。
- scp -pr build/libs/hello-world-0.0.1-SNAPSHOT.jar $USERID@$HOSTNAME:~/java-app/hello-world.jar
# 指定したコンテナが存在するかチェックする。
- CONTAINER_STATUS=`ssh $USERID@$HOSTNAME docker container ls -a -q -f name="$CONTAINER_NAME" | wc -c`
# コンテナが存在しない場合は新規作成、存在しない場合は再起動を行う。
- |
if [ $CONTAINER_STATUS -eq 0 ]; then
ssh $USERID@$HOSTNAME docker run -d -p $PORT:8080 -v /home/$USERID/java-app/hello-world.jar:/app/app.jar --restart=always --name $CONTAINER_NAME gitlab.example.com:4567/training/java-app
else
ssh $USERID@$HOSTNAME docker restart $CONTAINER_NAME
fi
# コンテナ停止用テンプレート
.stop_template: &stop
#image: ubuntu:20.04
variables:
GIT_STRATEGY: none
when: manual
#before_script:
#- apt-get update -y & apt-get install openssh-client -y
script:
# コンテナを削除する。
- ssh $USERID@$HOSTNAME docker rm -f $CONTAINER_NAME
# ステージングデプロイ
deploy staging:
<<: *deploy
stage: deploy staging
environment:
name: staging
url: $STAGING_DOMAIN
on_stop: stop staging
variables:
HOSTNAME: $STAGING_HOSTNAME
PORT: $STAGING_PORT
CONTAINER_NAME: $STAGING_CONTAINER_NAME
# ステージング停止
stop staging:
<<: *stop
stage: deploy staging
environment:
name: staging
action: stop
variables:
HOSTNAME: $STAGING_HOSTNAME
CONTAINER_NAME: $STAGING_CONTAINER_NAME
- gitでpushをすると、Gitlabサーバ上にコンテナが起動し、WEB画面が表示されるか確認する。また、Deployments - Environments - stagingでStopボタンを押すと、コンテナが削除されることも確認する。
- .gitlab-ci.ymlのSTAGING_HOSTNAMEやSTAGING_PORTを変更し、別のサーバでもデプロイ可能か確認する。また、ポートを追加することで複数コンテナへのデプロイも可能。
おわりに
もし、GitLab、GitLab Runnerの自動起動をやめたいときは、コンテナを削除しても、データは/srv配下に残るので問題ありません。ただし、パッケージは消えてしまいます。
今回の手順でGitlabの基本機能は理解できたかと思います。他にも、IssusやMerge requests, Wikiという機能もありますが、マニュアルを見ながらが、操作できると思いますので、ぜひ使ってみてください。
今後も、Moniter(Prometheus + Grafana)や、Infrastructure(Terraform)についても記事にしてみたいと思いますので、よろしくお願いいたします。
Discussion