2022/12/29 Kubernetes 1.24 に対応するよう情報を更新しました。
本記事の構成
やりたいことは主に以下の 2 点です。
- プライベートアクセス専用の EKS クラスターで actions-runner-controller を動作させたい
- GitHub API との通信はオンプレミスのプロキシサーバーを経由する
以下の構成で検証しています。
- Amazon EKS: Kubernetes 1.24
- actions-runner-controller: v0.26.0
- cert-manager v1.10.1
- eksctl: 0.124.0
- kubectl: v1.24.7
- AWS CLI: 2.9.11
actions-runner-controller とは
Kubernetes クラスター上で GitHub Actions の self-hosted runners を操作するためのコントローラーです。
以降はプライベートアクセス専用の EKS クラスターで actions-runner-controller を構築する際の流れを記載します。複数箇所でプロキシサーバーの接続情報の設定が必要になるため、そのあたりを中心に補足しています。
構築の流れ
Private EKS クラスターの構築
事前に作業環境に kubectl, eksctl, AWS CLI をセットアップしておきます。詳細な手順は割愛します。
eksctl によるプライベートクラスターの作成は以下のドキュメントを参照してください。
今回は以下のような Config File を使用して EKS クラスターを作成しました。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: actions-runner
region: ap-northeast-1
version: "1.24"
privateCluster:
enabled: true
skipEndpointCreation: true
vpc:
subnets:
private:
ap-northeast-1a:
id: subnet-xxxxxxxxxxxxxxxxx
ap-northeast-1c:
id: subnet-yyyyyyyyyyyyyyyyy
ap-northeast-1d:
id: subnet-zzzzzzzzzzzzzzzzz
プライベートアクセス専用のクラスターの場合、以下の VPC エンドポイントが必要になります。
- ECR (
ecr.api
,ecr.dkr
) - S3 (Gateway 型
s3
) - EC2 (
ec2
) - STS (
sts
) - CloudWatch Logs (
logs
)
eksctl でプライベートクラスターを有効化 (privateCluster.enabled
) した場合、自動的にこれらのエンドポイントが作成されます。 今回は Direct Connect で接続済みの VPC を使用したいという要件があり、既存の VPC とエンドポイントを利用するため、privateCluster.skipEndpointCreation
でエンドポイントの作成はスキップさせています。
既存の VPC を指定する場合、eksctl はルートテーブルを編集します。
ただしサブネットがメインのルートテーブルに紐づいている場合、eksctl はルートテーブルを編集しません (クラスターの作成に失敗します)。そのため明示的なルートテーブルの作成と紐づけを行なっておく必要があります。
eksctl はプロキシサーバーを介して EKS の AWS API と通信します。ただしプライベート EKS クラスターのエンドポイントに対する通信はプロキシを使用しないため、以下のような環境変数をあらかじめ設定しておきます。
export https_proxy=http://xxx.xxx.xxx.xxx:yyyy
export no_proxy=.eks.amazonaws.com
2022/12/19 に EKS が PrivateLink をサポートしたため、 AWS API に対する通信も VPC エンドポイント経由とすることができるようになりました。
以下のコマンドでクラスターを作成します。プライベートクラスターは通常のクラスターの作成より時間がかかります。今回の構成では 22 分程度でしたが、VPC や VPC エンドポイントを作成する場合はさらに時間がかかるので必要に応じてタイムアウト値を調整してください。
$ eksctl create cluster -f private-cluster.yaml
# タイムアウト値を伸ばす場合
$ eksctl create cluster --timeout 60m -f private-cluster.yaml
マネージドノードグループの登録
マネージドノードグループで使用する起動テンプレートに UserData を追加し、containerd がプロキシを使用するように構成します。
以下のブログを参考にさせていただきました。ありがとうございます。
こちらのブログの場合、Docker デーモンに対するプロキシを構成していますが、Kubernetes 1.24 以降では dockershim が削除されているため、以下のように containerd に対する設定に変更する必要があります。
Content-Type: multipart/mixed; boundary="==BOUNDARY=="
MIME-Version: 1.0
--==BOUNDARY==
Content-Type: text/cloud-boothook; charset="us-ascii"
# Set the proxy hostname and port
PROXY=${ProxyIP}:${ProxyPort}
MAC=$(curl -s http://169.254.169.254/latest/meta-data/mac/)
VPC_CIDR=$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/$MAC/vpc-ipv4-cidr-blocks | xargs | tr ' ' ',')
# Create the containerd systemd directory
mkdir -p /etc/systemd/system/containerd.service.d
# Configure containerd with the proxy
cloud-init-per instance containerd_proxy_config tee <<EOF /etc/systemd/system/containerd.service.d/http-proxy.conf >/dev/null
[Service]
Environment="HTTP_PROXY=http://$PROXY"
Environment="HTTPS_PROXY=http://$PROXY"
Environment="NO_PROXY=172.20.0.1,$VPC_CIDR,localhost,127.0.0.1,169.254.169.254,.internal,s3.amazonaws.com,.s3.ap-northeast-1.amazonaws.com,api.ecr.ap-northeast-1.amazonaws.com,dkr.ecr.ap-northeast-1.amazonaws.com,ec2.ap-northeast-1.amazonaws.com,ap-northeast-1.eks.amazonaws.com"
EOF
# Reload the daemon and restart docker to reflect proxy configuration at launch of instance
cloud-init-per instance reload_daemon systemctl daemon-reload
cloud-init-per instance enable_containerd systemctl enable --now --no-block containerd
--==BOUNDARY==
起動テンプレートを作成したら以下のような Config File でマネージドノードグループを作成します。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: actions-runner
region: ap-northeast-1
managedNodeGroups:
- name: t3s-proxy
desiredCapacity: 1
privateNetworking: true
launchTemplate:
id: lt-xxxxxxxxxxxxxxxxx
version: "1"
create nodegroup でマネージドノードグループを作成します。
$ eksctl create nodegroup -f nodegroup.yaml
actions-runner-controller の導入
actions-runner-controller は Admission Webhooks の証明書管理に cert-manager を使用するため、事前にインストールしておきます。
$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml
actions-runner-controller は Helm ではなく、kubectl でデプロイする前提で記載しています。
プロキシ環境下で actions-runner-controller を使用するには、以下の 3 箇所でプロキシサーバーの情報を設定する必要があります。
- controller-manager の manager コンテナ
- RunnerDeployment の runner コンテナ
- RunnerDeployment の sidecar (dind) コンテナ
1 は controller-manager の Deployment 定義に https_proxy 環境変数を設定します。
2,3 は RunnerDeployment の定義に https_proxy 環境変数を設定します。
1 については actions-runner-controller のマニフェストファイルを作業環境にダウンロードし、以下の箇所を直接追記しました。
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
control-plane: controller-manager
name: controller-manager
namespace: actions-runner-system
spec:
replicas: 1
selector:
matchLabels:
control-plane: controller-manager
template:
metadata:
labels:
control-plane: controller-manager
spec:
containers:
- args:
- --metrics-addr=127.0.0.1:8080
- --enable-leader-election
command:
- /manager
env:
- name: GITHUB_TOKEN
valueFrom:
secretKeyRef:
key: github_token
name: controller-manager
optional: true
- name: GITHUB_APP_ID
valueFrom:
secretKeyRef:
key: github_app_id
name: controller-manager
optional: true
- name: GITHUB_APP_INSTALLATION_ID
valueFrom:
secretKeyRef:
key: github_app_installation_id
name: controller-manager
optional: true
- name: GITHUB_APP_PRIVATE_KEY
value: /etc/actions-runner-controller/github_app_private_key
+ - name: http_proxy
+ value: "http://xxx.xxx.xxx.xxx:xxxx"
+ - name: https_proxy
+ value: "http://xxx.xxx.xxx.xxx:xxxx"
+ - name: no_proxy
+ value: "172.20.0.1,*.eks.amazonaws.com"
image: summerwind/actions-runner-controller:v0.22.3
name: manager
kubectl create でデプロイします。
$ kubectl create -f actions-runners-controller.yaml
Kubernetes 側の既知の問題により、apply ではなく create (更新時は replace) を使用する必要があります
GitHub API の認証には GitHub App または Personal Access Token (PAT) を使用できますが、今回は PAT 認証で検証しています。ランナーの種類に応じてトークンに 適切なスコープ を設定し、secret を作成します。
kubectl create secret generic controller-manager \
-n actions-runner-system \
--from-literal=github_token=${GITHUB_TOKEN}
PAT を使用して SAML SSO が構成されている Organization にアクセスする場合は、PAT を事前に認可 しておく必要ありますのでお忘れなく。
2,3 については以下のような定義で RunnerDeployment を作成しました。3 について補足すると GitHub Actions のジョブ内でコンテナを利用する際は、RunnerDeployment の sidecar として起動される dind の docker コンテナが使用されます。Kubernetes 1.24 での dockershim の削除は dind には影響を与えません。
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
name: runner-deploy
spec:
template:
spec:
enterprise: <enterprise-name>
labels:
- runner-container
containers:
- name: runner
env:
- name: RUNNER_FEATURE_FLAG_EPHEMERAL
value: "true"
- name: http_proxy
value: "http://xxx.xxx.xxx.xxx:yyyy"
- name: https_proxy
value: "http://xxx.xxx.xxx.xxx:yyyy"
- name: no_proxy
value: "172.20.0.1,10.1.2.0/24,*.eks.amazonaws.com"
- name: docker
lifecycle:
postStart:
exec:
command:
- sh
- -c
- "mkdir -p $HOME/.docker/ && echo '{ \"proxies\": { \"default\": { \"httpProxy\": \"http://xxx.xxx.xxx.xxx:yyyy\", \"httpsProxy\": \"http://xxx.xxx.xxx.xxx:yyyy\"} } }' > $HOME/.docker/config.json"
env:
- name: http_proxy
value: "http://xxx.xxx.xxx.xxx:yyyy"
- name: https_proxy
value: "http://xxx.xxx.xxx.xxx:yyyy"
- name: no_proxy
value: "172.20.0.1,10.1.2.0/24,*.eks.amazonaws.com"
---
apiVersion: actions.summerwind.dev/v1alpha1
kind: HorizontalRunnerAutoscaler
metadata:
name: runner-deployment-autoscaler
spec:
scaleDownDelaySecondsAfterScaleOut: 300
scaleTargetRef:
name: runner-deploy
minReplicas: 1
maxReplicas: 5
metrics:
- type: PercentageRunnersBusy
scaleUpThreshold: '0.75'
scaleDownThreshold: '0.25'
scaleUpFactor: '2'
scaleDownFactor: '0.5'
マニフェストをデプロイします。
$ kubectl apply -f RunnerDeployment.yaml
Runner の pod が正常に起動していることを確認できれば、GitHub 側からも対象の Runner が見えているはずです。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
pod/runner-deploy-xxxxx-xxxxx 2/2 Running 0 53s
controller-manager が正常に起動しない場合は 1 または GitHub 側の設定を、Runner が正常に起動しない場合は、2 または 3 の設定 を確認してみてください。
以上です。
参考になれば幸いです。