背景
GitLab上でAWSのFargateを利用した独自のRunnerを実行させる手順になります。
普通にイメージを作成しただけだとタスクの量などに応じでスケーリングなどができないのですが、AWSのFargateを利用すればそれができます。
基本的な内容はAutoscaling GitLab CI on AWS Fargateに準じていますが、一部古い内容になっているため手順等が異なる場合があります。
要件
- EC2, ECS, ECRを作成、変更できる権限を持つアカウント
- AWS VPCとサブネット
- 一つ以上のAWSのセキュリティグループ
環境構築
Fargate用のコンテナイメージの作成
ここではGitLab Runnerとして動かすDockerのイメージを作成します。
どういうものかというとRunner ImagesのGitLabバージョンのようなものです。
色んな機能が入っていれば入っているほどよいですが、無駄な機能はあればあるだけ重いので実際に必要なものだけ入れておけばよいでしょう。
今回、必要だった機能はNode16.18.1とRuby3.3.0が動く環境でしたので、そのDockerイメージを作成します。
Node 12.16の例が載っていますが、イメージ自体にGitLab Runnerがインストールされている必要があります。EC2のホスト自体にもインストールされている必要があるので、混同しやすいので注意しましょう。
また、コンテナは公開鍵認証によるSSH接続を受け入れることができるようになっていなければいけません。
それがこのdocker-entrypoint.shに該当する箇所になります。
要するにホストマシンからFargateが立ち上がるときに認証情報としてSSH_PUBLIC_KEY
が送られてくるので、それをちゃんと受け取れなければいけないということなのだと思います、多分。
FROM gitlab/gitlab-runner:latest
ARG TINI_VERSION=v0.19.0
ENV PATH /root/.rbenv/shims:/root/.rbenv/bin:$PATH
ENV RUBYOPT -EUTF-8
COPY --from=node:16.18.1 /usr/local/bin/node /usr/local/bin/node
RUN curl -Lo /usr/local/bin/tini https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-amd64 \
&& chmod +x /usr/local/bin/tini
RUN apt-get update
RUN apt-get -y install git curl libssl-dev libreadline-dev zlib1g-dev autoconf bison build-essential libyaml-dev libreadline-dev libncurses5-dev libffi-dev libgdbm-dev openssh-server
RUN mkdir -p /var/run/sshd
EXPOSE 22
RUN git clone https://github.com/rbenv/rbenv.git ~/.rbenv
RUN echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
RUN echo 'eval "$(rbenv init -)"' >> ~/.bashrc
RUN git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
RUN ~/.rbenv/bin/rbenv install 3.3.0
RUN ~/.rbenv/bin/rbenv global 3.3.0
RUN ~/.rbenv/bin/rbenv exec gem install bundler
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["tini", "--", "/usr/local/bin/docker-entrypoint.sh"]
今回はこのようなDockerイメージを作成しました。
#!/bin/sh
if [ -z "$SSH_PUBLIC_KEY" ]; then
echo "Need your SSH public key as the SSH_PUBLIC_KEY env variable."
exit 1
fi
# Create a folder to store user's SSH keys if it does not exist.
USER_SSH_KEYS_FOLDER=~/.ssh
[ ! -d "$USER_SSH_KEYS_FOLDER" ] && mkdir -p $USER_SSH_KEYS_FOLDER
# Copy contents from the `SSH_PUBLIC_KEY` environment variable
# to the `${USER_SSH_KEYS_FOLDER}/authorized_keys` file.
# The environment variable must be set when the container starts.
echo $SSH_PUBLIC_KEY > ${USER_SSH_KEYS_FOLDER}/authorized_keys
# Clear the `SSH_PUBLIC_KEY` environment variable.
unset SSH_PUBLIC_KEY
# Start the SSH daemon.
/usr/sbin/sshd -D
Dockerfileができたらビルドを実行します。
必要かどうかはわからないのですが、実際にFargateで動かすDockerはx86_64を想定しているので、
docker build --platform=linux/amd64 -t ruby3.3.0-node16.18.1-runner .
としてアーキテクチャをlinux/amd64を指定します。
コンテナイメージをレジストリに登録
イメージが作成できたらECRにイメージをプッシュしてレジストリとして登録します。
ここはECRからView Push Commandsを押せばコマンドが表示されるのでそれを利用すれば良いです。
EC2インスタンス作成
- EC2を開く
- Ubuntu 22.0.4(引用元では18.0.4を利用しているが流石に古いので)でインスタンスで
gitlab-runner-micro
という名前で作成する- キーペアの作成などがあるのでまだインスタンスの作成ボタンを押してはいけない
- Configure Instance Detailsを開く
- Number of instancesを設定する
- NetworkでVPCを選択する
- Auto-assign Public IPを有効化する
- IAM roleで新しいIAMロールを作成し、AmazonECS_FullAccessを割り当てる
- 新しいIAMロールはここでは仮に
ec2-gitlab-runner
とする
- 新しいIAMロールはここでは仮に
- EC2の画面に戻りインスタンス一覧に戻る
gitlab-runner-micro
にセキュリティグループにはSSH(22)を割り当てる- こうすることでSSHでマシンに接続ができるようになる
- キーペアを作成し
ec2-gitlab-runner.pem
というファイルおwダウンロードして保存する- 名前は何でも良いが、一度この鍵を失うと二度とダウンロードできないので注意すること
- インスタンスを作成するとIPv4が表示されているのでこの値をメモしよう
GitLab Runnerのインストール
GitLabのウェブサイトからプロジェクトを開きSettings > CI/CDからSetup a specifig Runner manuallyを選択してURLとRegistration Tokenの値をメモする。
ダウンロードしたec2-gitlab-runner.pem
を利用してEC2インスタンスに接続する。
インスタンスのIPv4がaaa.bbb.ccc.ddd
であれば、
ssh [email protected] -i ec2-gitlab-runner.pem
でログインができるので、ログインができたら下記のコマンドでGitLab Runnerをインストールする。
sudo mkdir -p /opt/gitlab-runner/{metadata,builds,cache}
curl -s "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt install gitlab-runner
インストールができたら、先ほどメモしたURLとRegistration Tokenを利用して、
sudo gitlab-runner register --url **URL** --registration-token **REGISTRATION_TOKEN** --name **RUNNER_NAME** --run-untagged --executor custom -n
でGitLabにEC2のGitLab Runnerを登録する。
RUNNER_NAME自体はGitLabで識別するためだけの名前なので何でも良い(多分)ので今回は適当にgitlab-runner-dev
とした。
次にsudo vim /etc/gitlab-runner/config.toml
を以下のように編集する
concurrent = 1 # ここの値は弄らない
check_interval = 0 # ここの値は弄らない
[session_server]
session_timeout = 1800 # ここの値は弄らない
[[runners]]
name = "gitlab-runner-dev" # ここの値は弄らない
url = "https://gitlab.com/" # ここの値は弄らない
token = "__REDACTED__" # ここの値は弄らない
executor = "custom" # ここの値は弄らない
builds_dir = "/opt/gitlab-runner/builds"
cache_dir = "/opt/gitlab-runner/cache"
[runners.custom]
config_exec = "/opt/gitlab-runner/fargate"
config_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "config"]
prepare_exec = "/opt/gitlab-runner/fargate"
prepare_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "prepare"]
run_exec = "/opt/gitlab-runner/fargate"
run_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "run"]
cleanup_exec = "/opt/gitlab-runner/fargate"
cleanup_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "cleanup"]
もしもプライベートCAを利用したセルフマネージドなインスタンスを使っている場合には、
[runners.custom]
volumes = ["/cache", "/path/to-ca-cert-dir/ca.crt:/etc/gitlab-runner/certs/ca.crt:ro"]
を付け加えること。
次にsudo vim /etc/gitlab-runner/fargate.toml
を実行してファイルを編集する。
LogLevel = "info"
LogFormat = "text"
[Fargate]
Cluster = "gitlab-runner-dev" # 要編集
Region = "ap-northeast-1" # EC2のリージョン
Subnet = "subnet-xxxxxx" # Networkingの項目
SecurityGroup = "sg-xxxxxxxxxxxxx" # Securityの項目(SSHを許可しているもの)
TaskDefinition = "ruby330-node16181-runner:1" # 要編集
EnablePublicIP = true
[TaskMetadata]
Directory = "/opt/gitlab-runner/metadata"
[SSH]
Username = "root" # ubuntuじゃなくてよいのかと思わなくもない
Port = 22
ここで設定する必要があるのは**[Fargate]**の五つの項目です。
ただし、現時点ではClusterとTaskDefinitionの値についてはわからないので、先にそれ以外の値から埋めます。
これについてはEC2インスタンス一覧から、先ほど作成したインスタンスを表示して入力します。
Regionに関しては東京を利用しているならap-northeast-1
となります。
ここまでできたら最後にFargate driverをインストールします。
sudo curl -Lo /opt/gitlab-runner/fargate "https://gitlab-runner-custom-fargate-downloads.s3.amazonaws.com/latest/fargate-linux-amd64"
sudo chmod +x /opt/gitlab-runner/fargate
ECS Fargate Clusterの作成
- Clustersからクラスターを作成
- Infrastructureで**AWS Fargate(serverless)**を選択
- 引用元ではNetworking onlyを選択しろとあるが、現在の選択項目にはそんなものはない
- 名前は
fargate.toml
で設定したものと同じ(今回の場合は)gitlab-runner-dev
を指定する - 作成する
- 作成したらUpdate Clusterを選択する
- Default capacity provider strategyから
FARGATE
を選択する - 更新を押して保存する
ECSタスク定義作成
- Task Definitionsを開く
- Launch typeで
AWS Fargate
を選択 - 名前は先ほど
fargate.toml
で設定したものと同じ(今回は)ruby330-node16181-runner
を設定:1
のようなサフィックスは不要
- ポートマッピングで22/TCPを受け付けてSSH接続できるようにします
- 保存
テスト
ここまでできたら設定は完了なので、適当にGitLabからジョブを割り当ててみましょう。