お元気そうで残念です

もんじゃ焼きが転がってるところにいます。

actions-runner-controller使ってみた

最近とあるCIからGIthub Actionsに移行するタスクをしています。 コード管理はGithub Enterprise Serverを使っているため、Github-hosted Runnerを使えず、良い感じにself-hosted runnerを実行する方法を探していたところ、こちらを見つけました。

github.com

製作者の紹介記事はこちら

GitHub Actions の Runner の運用を自動化する | SummerWind

メリット、デメリット 使用感などをまとめていきます。

メリット

冪等性がある

公式の手順通りに実行するとjob終了後もrunnerタスクは残り続けるし、VM内で変更したファイルもそのままです。 このcontrollerでは受け取ったjobを実行するごとにpodが再作成されるため、冪等性があります。

オートスケールする

kubernetesで動作するため当たり前ですがオートスケールさせることが出来ます。 溜まっているqueueに応じてオートスケールします。

デメリット

kubernetes clusterを管理する必要がある

self-hosted runnerのためだけにclusterを管理する必要があります。
インスタンスコストはもちろん、運用コストも少なくないので本当にこのcontrollerを採用するべきなのか検討するべきです。
今回は利用するorganization、実行job数が多く、冪等性とオートスケールが必須要件でしたので採用しました。

docker in dockerになる

docker actionを実行する場合は、 sidecarで立ち上がるdockerコンテナ内で実行されます。(runner内での実行も可能) dindになるためprivileged: trueにする必要があり実行されるjobによっては危険です。

使用感

その他雑多なことを書いていきます。

使い方

詳しい設定手順は公式サイトのREADMEを参照してください。

GHES独自の部分やManifstなどについて触れていきます。

Personal Access Tokenの使用

GHESに接続するためにPersonal Access Tokenを設定します。
公式DocではGithub Appも使えると書いていますが、api urlがGHESのurlで更新されていないため、GitHub Appでは接続出来ないため注意してください。

kubectl create secret generic controller-manager \
    -n actions-runner-system \
    --from-literal=github_token=${GITHUB_TOKEN}

実行対象Repositoryを取得

HorizontalRunnerAutoscaler(HPAのRunner版 以下HRA)を正しく動作させるために実行対象Repositoryをmetrics.repositoryNamesに記載する必要があります。 Organaization内の全Repositoryは以下のコマンドで取得できるため、取得して設定してください。

curl -v -H "Authorization: token TOKEN" https://GHES_URL/api/v3/orgs/ORG/repos | jq -c -r '.[].name'

RunnerのManifest

Organization単位でRunnerを登録するManifestです。
実行ログを保存するためにsidecarでaws-cliコンテナを立てて、podが終了するときにS3に送信するようにしています。
HRAを正しく動作させるために先程取得したRepository名を設定してください。

apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
  name: ORG-runnerdeploy
spec:
  replicas: 1
  template:
    spec:
      labels:
        - test-runner
      initContainers:
      - name: chmod
        image: alpine
        command: ["chmod", "777", "/runner/_diag"]
        volumeMounts:
        - name: runner-log
          mountPath: /runner/_diag
      organization: ORG
      image: summerwind/actions-runner:v2.274.1
      dockerdWithinRunnerContainer: false
      env:
      - name: GITHUB_ENTERPRISE_URL
        value: "https://GHES_URL/"
      volumeMounts:
      - name: runner-log
        mountPath: /runner/_diag
      volumes:
      - name: runner-log
        emptyDir:
      sidecarContainers:
        - name: aws-cli
          image: amazon/aws-cli:2.1.1
          command: ["/bin/bash", "-c"]
          args: ["trap \"aws s3 cp /var/log/runner-log/Worker* s3://BUCKET/self-hosted-runner/`date +%Y/%m/%d/`  --region REGION\" TERM INT; sleep infinity & wait"]
          env:
          - name: AWS_ACCESS_KEY_ID
            valueFrom:
              secretKeyRef:
                name: aws-access
                key: aws_access_key_id
          - name: AWS_SECRET_ACCESS_KEY
            valueFrom:
              secretKeyRef:
                name: aws-access
                key: aws_secret_access_key
          volumeMounts:
          - name: runner-log
            mountPath: /var/log/runner-log

---
apiVersion: actions.summerwind.dev/v1alpha1
kind: HorizontalRunnerAutoscaler
metadata:
  name: ORG-runnerdeploy-autoscaler
spec:
  scaleTargetRef:
    name: ORG-runnerdeploy
  minReplicas: 1
  maxReplicas: 5
  scaleDownDelaySecondsAfterScaleOut: 300
  metrics:
  - type: TotalNumberOfQueuedAndInProgressWorkflowRuns
    repositoryNames:
    - repositoryA
    - repositoryB

ありがたいこと

Organization単位でRunnerを設定できるしオートスケールできる

RunnerとHRAをOrganization単位で設定できるので、複数Organization対応も簡単にできました。
他のツールだと複数Organizationは難しそうでしたので非常に感謝しています!

設定が楽

上記のManifestの通り設定が非常に簡単です。
Kubernetes Clusterを管理する点を除けば。

困っていること

キャッシュできない

actions-controller-runnerの問題ではなく、self-hosted runnerの問題です。
GHESで実行すると、キャッシュ出来ないので実行時間がかかりまくって使い物にならないのではという話がでています。

たまにrunnerが固まる

原因がつかめていないのですが、実行後のrunnerが削除されずqueueが溜まり続けることがあります。
runnerを手動で削除すると大体は解消しますが、たまにmanagerを再作成しないと直らないときもあります。

Repository名の設定が面倒

Repositoryが追加されると毎回Manifestに追加する必要があるため正直めんどい。
Issueは出ているので対応していただけることを切に願います。

Autoscaling for an organization runner · Issue #158 · summerwind/actions-runner-controller · GitHub

おわりに

self-hosted runnerをkubernetesで実行できるツールactions-runner-controllerを紹介しました。
非常に使いやすいポイントだらけですが、大本のrunnerの問題であるGHESでキャッシュができない点がネックです。
Githubが対応してくれないとプロダクトによっては使い続けることは難しいかもしれません。

FluentBitのログ欠損調査&対策

EKSでFluentBitを使ってログ転送をしています。

別環境からEKSへの移設期間で双方のログを比較していたところ、EKS環境でログ欠損がかなり起きていることが分かり、対策でやったことを書いていきます。

対策

ログを確認する

FluentBitのログを見てみると以下の2つのログが出ていました。
Kinesisのログはretryされるので問題ないはずですが、mem buf overlimitはアウトです。

[ warn] [input] tail.0 paused (mem buf overlimit)
level=warning msg="[kinesis 0] 34/500 records failed to be delivered. Will retry.\n"

podのmemory request/limitを上げる

mem buf overlimitが出ていたのでmemory sizeを増やしましょう。
今回はここは足りていましたが一応記載します。

resources:
  limits:
    memory: 750Mi
  requests:
    memory: 500Mi

Mem_Buf_Limitを上げる

podのmemoryは十分確保されていましたが、FluentBitのconfigでtail inputプラグインでMem_Buf_Limitが非常に低い値になっていました。 ここも余裕のある値にしておきます。

Tail - Fluent Bit: Official Manual

Mem_Buf_Limit     500MB

メモリ監視を入れる

これでも十分な値かは判断出来ないので、Datadog等でメモリ使用量を監視しましょう。
上限に引っかかるようであれば適宜増強します。

カスタムメトリクスを収集する

FluentBitはprometheusエンドポイントを作成出来ます。

Monitoring - Fluent Bit: Official Manual

Datadog等でメトリクスを収集するようにしましょう。
今回は収集しても怪しいデータは取れませんでした。

  template:
    metadata:
      labels:
        name: fluentbit
      annotations:
        ad.datadoghq.com/aws-for-fluent-bit.check_names: |
          ["prometheus"]
        ad.datadoghq.com/aws-for-fluent-bit.init_configs: |
          [{}]
        ad.datadoghq.com/aws-for-fluent-bit.instances: |
          [
            {
              "prometheus_url": "http://%%host%%:2020/api/v1/metrics/prometheus",
              "namespace": "fluentbit",
              "metrics": [
                "fluentbit_input_records_total",
                "fluentbit_input_bytes_total",
                "fluentbit_output_proc_records_total",
                "fluentbit_output_proc_bytes_total",
                "fluentbit_output_errors_total",
                "fluentbit_output_retries_total",
                "fluentbit_output_retries_failed_total"
              ],
              "tags": [
                "service_code:fluent-bit",
                "component:fluent-bit",
                "role:flunt-bit",
                "service_group:daemonset"
              ]
            }
          ]

Buffer_Chunk_SizeとBuffer_Max_Sizeを増やす

This value is used to increase buffer size.

ということなので増やすべきでしょう。これに関する不審なログは出ていませんでしたが1MBまで増やしました。

Buffer_Chunk_Size 1MB
Buffer_Max_Size   1MB

Tail - Fluent Bit: Official Manual

どうしても欠損してしまうときは?

色々やっても欠損してしまう場合は諦めましょう! ログで送るのではなくDBに直接書き込むようにすべきです。

GCPでIAM conditionをいじったあとterraformが通らなくなった貴方へ

以下のエラーで悩んでる自分に贈るメモ。

googleapi: Error 400: Requested policy version (1) cannot be less than the existing policy version (3). For more information, please refer to https://cloud.google.com/iam/docs/policies#versions., badRequest

解決方法

provider "google-beta" のversion 2.20.1以上を使う。

Error 400: Requested policy version (1) cannot be less than the existing policy version (3) · Issue #5218 · terraform-providers/terraform-provider-google · GitHub

ここを見て provider "google"のversion 2.20.1以上を試して解決せず悩んでいたが、"google-beta"を使う必要があった。

このエラーになった経緯

  • Terraformでservice_account(google_service_account)やiam(google_project_iam_member)を設定していた。
  • 諸事情でIAM conditionをweb consoleから設定した。
  • IAM policyの実態がversion 3になった。 https://cloud.google.com/iam/docs/policies#versions
  • Terraformでiam(IAM policyを設定したものとは別のもの)をいじろうとした。
  • version違うからダメやでと言われるようになってしまった。