kanikoをAWS CodeBuildで使う

最近kanikoの話題を見るようになってきて,どういう動作をするのかなと気になり触ることにした.

普段はGCPではなくAWSの方を使っているのもあり,CodeBuildの方でもkanikoを使えないかと試してみたメモ.

動かすまでに試した記録と動作するサンプルリポジトリを以下に書いていく.

gcr.io/kaniko-project/executorはCodeBuildでは利用できない

まずハマったこととして,公式で提供されているイメージはCodeBuild上で動かすには様々な問題があり,利用することができない.

そのハマった点とその対処を順に書いていく.

CodeBuildではscratchイメージを動かすことができない

CodeBuildのベースイメージとしてgcr.io/kaniko-project/executorを指定すると.以下のようなエラーが出てしまい実行することができない.

SINGLE_BUILD_CONTAINER_DEAD: Build container found dead before completing the build. Build container died because it was out of memory, or the Docker image is not supported*1

いくつか実験してみると,これはexecutorのイメージがscratchベースであるためだということがわかり,おそらくCodeBuildの実行に必要なものが何か揃っていないと考えることができる.*2

kanikoにはgcr.io/kaniko-project/executor:debugというshellとbusyboxが追加で入ったイメージも用意されているが,こちらも同様にエラーになってしまい使うことができない.

alpineイメージは以前にCodeBuild上で動作することを確認していたため*3,今回も最終イメージをalpineに変更することで回避することができた.

CodeBuildで動かすためのPATHが不十分

利用するイメージをalpineに変更したところ,今度は以下のような別のエラーが発生した.

Internal Service Error: CodeBuild is experiencing issues

このエラーでGoogle検索しても1件しかヒットせず,しかもあまり参考にならないと思われる情報*4だったため,しばらくは解決方法がわからない状態だった.

そんな中,executorのDockerfileを見るとPATH/usr/local/bin:/kanikoしか書いていない*5という事に気づき,もしやと思って/bin/usr/binを追加したところ動作するようになった.

以上の対応を踏まえて,CodeBuildで動かすことのできるkanikoのalpineベースのイメージを作成した.

https://hub.docker.com/r/cohalz/kaniko-alpine

公式イメージの中身をそのまま持ってきているのもあり,公式イメージの代わりとしてCodeBuild以外でも使うことができる.

また,公式のdebugイメージと同様にshellやbusyboxも使えるようになるのでデバッグ時に便利である.

docker run -v $(pwd):/workspace -it --entrypoint="" cohalz/kaniko-alpine sh

実行コマンドをCodeBuildの形式に合わせる

GCPのCloud Buildでは実行したいコンテナとその引数を書いていく形式*6なのに対し,AWSのCodeBuild(や他のCIサービス)は実行環境がコンテナの内部になるほか,その環境で実行したいシェルスクリプトを書くという形式*7になっている.

そのため,CodeBuildで実行する際には,Cloud Buildで指定した引数の前にコマンド名である/kaniko/executorと,コンテナ内で実行するということで--forceオプションの2つを追加する必要がある.

つまり,CodeBuild上でビルドできるか確認するための最低限のbuildspec.ymlはこうなる.

version: 0.2

phases:
  build:
    commands:
      - /kaniko/executor --force --no-push"

CodeBuildからECRにpushできるようにする

上のを踏まえ,buildspec.ymlをこのように書くことでECRにpushできるようになる.

version: 0.2

phases:
  build:
    commands:
      - echo "{\"credsStore\":\"ecr-login\"}" > /kaniko/.docker/config.json
      - /kaniko/executor --force -d "${ECR_REPO}"

コマンドの一行目はECRへプッシュする際に必要で,kanikoではECRへプッシュする際には/kaniko/.docker/config.jsoncredsStoreもしくはcredHelpersにECRを使えるような変更が必要なための対応になる.*8

ECRの認証はCodeBuildのロールを使うため,そのロールにECRへpushする権限も必要.

CodeBuildの動作確認用のリポジトリ&CloudFormation

CodeBuildで動作するkanikoイメージを作ったので,動作確認がしやすいようにサンプルプロジェクトとCloudFormationテンプレートを作ってみた.

github.com

リポジトリにあるexample/using-kaniko-image/template.ymlファイルをデプロイすることで,このリポジトリにあるDockerfileをkanikoを使ってビルドしECRにpushするという動作を確認することができる.

実行するとこのようにCodeBuildのビルドログがkanikoの表示になっているのが確認できる.

f:id:cohalz:20190610003852p:plain
CodeBuildのコンソール画面

終わりに

動かすまでが意外と大変だったけど,終わってみると結構簡単に使えるようにできたので良かった.

CodeBuildはローカルやS3のキャッシュも使えるのでkanikoとの相性もいいと思う(権限もCodeBuildのロールで制御できる).

CodeBuildは元からBuildKitも利用できるので,kanikoとBuildKitのどちらを使うか適材適所で選んでいけると良いと思う.

s3 syncを定期実行するDockerイメージを作った

リポジトリは以下.イメージはcohalz/cron-s3-syncで利用可能.

github.com

以下のように実行するとyour-bucketというS3バケットにあるファイル群を/tmp/dir/ 以下に同期することができる.

docker run --init \
  -e "AWS_ACCESS_KEY_ID=xxxxxxxxxx" \
  -e "AWS_SECRET_ACCESS_KEY=xxxxxxxxxx" \
  -e "S3_BUCKET=your-bucket" \
  -e "LOCAL_DIR=/tmp/dir/" \
  -e "SYNC_TYPE=PULL" \
  cohalz/cron-s3-sync

同期は毎分実行され,変更のあったファイルだけが更新される.

逆にS3へバックアップしたいときにはSYNC_TYPE=PUSHとすることで,毎分S3へ同期させることができる.

主な用途として,別のコンテナで使うファイルを更新させたい場合に使える.このコンテナをサイドカーとして動かしボリュームを共有することで,その別のコンテナには手を加えずS3経由でファイルを更新することができる.

例えばEnvoyのDynamic configurationではファイルの更新を検知して再読込ができる*1ので,設定変更がEnvoyコンテナの入れ替えやコントロールプレーンの実装なしに実現できるようになる.*2

株式会社はてなに入社しました

id:cohalzです.2018年8月付で株式会社はてなに入社しました.

職種はSRE (Site Reliability Engineer) で,勤務地は京都です.

株式会社はてなに入社しました - hitode909の日記

まえがき

はてなとの出会いは、2017年のはてなインターンに参加したことがきっかけでした。 はてなインターンの特徴の一つに、ほとんどの参加者が参加したときの内容をブログ記事として書いていることがあります。インターン参加記事には、技術やWebに対する大きな熱量がこもっており、すっかり自分もWeb技術をやっていくのだと感化されました。 ダメ元で選考に望んだところ、運良く選考通過のお知らせをいただいてとてもうれしかったことを今もよく覚えています。 そこから毎年インターンの参加者をみてきていますが、とてもハイレベルで、よく自分が選考通過したものだと今でも思います。 この出来事が自身の人生にとって大きな転機だったと言えるでしょう。

インターンの2ヶ月後にアルバイトスタッフとして入社し、配属されたのは、はてなのITインフラを担当するシステムプラットフォーム部という部署でした。 今でこそ当たり前のようにSREのような基盤技術を専門としていますが、当時はサービス開発をするアプリケーションエンジニアを志望していました。 しかし、システムプラットフォーム部での仕事を通して、サーバがたくさんあってそれらが相互に通信してひとつの系をなすというWebシステムに魅せられ、今でいうところのSREを志しました。インターン中に行われたid:masayoshi さんによるインフラ講義に感銘を受けたことも影響しています。はてなでインフラ研修を受けました - Re:cohalz の記事にて、アルバイト時代に、何を学んだかを書いています。 そこから新卒で内定をいただいたにも関わらず、大学院を中途退学してしまいましたが、その後も快く受け入れてくださったはてなにはとても感謝しています。*1

正社員として入社してから既に半年以上,アルバイトを含めると1年以上はてなで働いていたので,この機会に振り返ってみようと思います.

アルバイト時代

アルバイトとして入社した2017年11月時点では,ミドルウェア,Linux,クラウドサービスのことは何もわからない状態でした.

そんな中,最初にアサインされたタスクはLet's Encrypt証明書を自動で取得・更新するという基盤作成のタスクでした.

このタスクをアサインされた当時の状態でわからないことで言うと,

  • Let's Encryptって怪しいものだと思っていた.
  • AWS CLIはおろかAWS自体何一つ触ったこと無い
    • 何をしたらどういった変化が起こるのかわからず,とにかく操作が怖い
  • webサーバってどうやって立てるの?
    • セキュリティグループってやつで80番開放したら立つのかと思ってた
    • nginxはなんて読むのかは知ってるけど何なのか知らない

と言うレベルで,とにかく1から進めていきました.

そんな状態で本当にやっていけるのか,もちろん不安ではありました.

しかし,所属していたチームの座談会を見たところ,その不安はなくなりました.

hatenacorp.jp

この記事では,当時アルバイトメンターをしてくれていた id:dekokun さんや,まだ新卒入社して年数の経っていない id:taketo957 さんや,雲の上の存在だった id:y_uuki さんまでも昔からインフラに詳しいわけではなかったという事実が助けになりました.

アルバイトでは研修と,AWSを中心とした運用・基盤作成を主なタスクとしていました.

研修の内容については上に書いてありますが,その結果Chefやkeepalivedなどのオペレーションはできるようになり,関連ツールも作成することもありました.

github.com

研修内容は入社した今でも役に立っていて,最近ではアプリケーションエンジニアにkeepalivedの挙動を教えたり,同じチームとなった id:hokkai7go さんにChefを教えるといった事もありました.

AWSについてもどんどん理解を深めていき,入社前には既にLambdaを利用した基盤ツールを多く作成できました.

上に書いたLet's Encrypt証明書の基盤もLambdaで動いており,ブログに書いたところ,大きな反響があって嬉しかったのを覚えています.

developer.hatenastaff.com

ちなみに,今年の1月に行われた「Hatena Engineer Seminar #11」にて発表した内容はすべてアルバイト時代に作成したものになります.

資料はこちらです.

入社後

8月に正社員として入社して,初めて渡されたタスクはかなり印象に残っています.

タスクはデータセンターで使っているサービスのログ経路を変更するというものでした.

近い内にでログを保存しているホストのストレージが枯渇するため,それまでにディスクの交換が必要になっていました.

そしてそのディスクを交換する作業というのは大変だったので,「そのホストを使わないような配送経路を作成し切り替えることでディスク交換を不要にする」ということを行いました.

結果的にできた配送の仕組みとしては単純にcronでS3に定期的にアップロードするというだけでしたが,難しいところがいくつかありました.

例としては,

  • アクセスログも含まれているので欠損してはならない
    • 配送に問題があったことを気がつけるようにしたい
  • ログの配送によってネットワーク帯域を潰してはいけない

欠損の対策として,S3側ではクロスリージョンレプリケーションを利用しました.

また,S3にアップロードする際にエラーが起こった場合,ファイルが欠損することはあるのか,という部分についても検証を行ってから進めました.

また,ログ配送の際にエラーが起きていると配送元のディスク容量枯渇したり,欠損が起きる可能性があったので監視設定も追加しました.

監視ではcron実行時にエラーが起きていないか,そもそもcronが実行されているのか気がつけるように,horensoとMackerelのチェック監視(check-file-age)を組み合わせて監視を行いました,

これによりcronの成否確認およびcron自体が実行されているかの確認が行えるようになりました.

ネットワーク帯域に関しては,様々なサービスのログが流れてくるというものもあり,S3にアップロードする際に帯域を潰さないように配慮する必要がありました.

aws cliでの帯域制御や社内で利用しているフォワードプロキシを利用することで,帯域に配慮したログ配送を実現しました.

以上により配送経路の変更が完了し,今まで使っていたストレージにログが転送されないことが確認できました.

f:id:cohalz:20190331031832p:plain
ストレージ容量が枯渇する前に対応が完了した

また,この作業と並行して,はてなインターン2018において,前半後半どちらともメンター業も行いました.

developer.hatenastaff.com

後半過程ではアプリケーションをコンテナで動かすための検証をインターン生と一緒に行っていました.

developer.hatenastaff.com

この当時はコンテナやECS/Fargateについて全然知らなかったのですが,この検証をもとに社内でコンテナ化を進めていこうという気持ちになりました.

そしてありがたいことに,現在では社内でコンテナ化を進めていくプロジェクトのメインエンジニアとして活動をしています.

そしてつい最近に,本番で稼働しているアプリケーションの一つをコンテナ化・ECS移設を無事成功することができました.

コンテナ化以外の活動としては,AWS CDKというアプリケーションに興味を持ち,バグ報告やプルリクエストなども積極的に行っているというのがあります.

Issues · awslabs/aws-cdk · GitHub

AWS CDKを使って社内用のECSクラスタを簡単に作成するライブラリを作るなどもしていました.

これらのように,今までインフラ側ではなくアプリケーションのコードを書いていた経験が生きていると感じる事が増えていて,こんな自分でも役に立つことがあるんだと思うようになってきました.

アルバイト入社当時は「自分はこんなにインフラのこと何もわからないのに役に立つとは思えなかった」のですが,以上の経験からある程度のインフラ知識を獲得し,さらに元々ある程度持っていたコードを書く能力が合わさり,自分の強みとなりつつあるのを感じています.

こんな何もできなかった自分を拾ってくれてありがとうございます.

これからもよろしくお願いします.

好きなゲーム音楽家,あるいはアーティストの話

好きなアーティスト何?とか普段何聴いてるの?と聞かれると答えにくい.

何故かと言うと普段はゲーム音楽を聴いていて,一般的なアーティストの名前は全くわからないから.

とはいってもゲーム音楽の中でも好きな音楽家はいて,その紹介をする.

今回紹介するのは下田祐と言う人.

現在はタイトーのサウンドチームであるZUNTATAで活動しており,プログレ系の音楽とFM音源を用いた作曲,およびライブパフォーマンスに定評がある.

知ったきっかけ

2010年(9年前!)に買った東方紫香花という東方Projectのアレンジコンピレーションアルバムで知る.

その後2017にタイトーのサウンドチームであるZUNTATAに移籍すると言うタイミングから本格的にハマり,追いかけているという状態.

商業で活動している他,東方やボーカロイドなどで同人活動も行っていて,活動の幅が広い.

Spotifyのリンクを載せるが,Apple Musicなど他の配信サービスでも視聴可能.

歴史

同人

2003 ~ 2013年ごろの活動.

初期にはゲーム音楽のアレンジをしていたほか,東方アレンジもしていた.

東方アレンジでは,原曲の他に何かのオマージュが入っていることが多く,知っているとより楽しめる曲が多い.

2010年代になるとボーカロイド関連のアルバムを多く出すようになり,メグッポイド3周年記念祭にも参加している.

karent.jp

また,初期のボーカロイドユーザでもある.

東方アレンジやボーカロイドだけではなく,チップチューンでも活動している.

FAMICOMPOというファミコン音源を用いたコンテストに出場していたり,

www.youtube.com

オリジナルのアルバムもリリースしている.

open.spotify.com

ほかサークルのコンピレーションアルバムへの参加も多く,2005年にリリースされた東方紫香花もその一つ.

ほかだと2014年にリリースされたCradle Re:BOOTという4枚組アルバムにも参加している.

Cradle Re:BOOT - 東方幻樂祀典 - sound sepher

プログレバンド

新世界というプログレバンドを結成し,2004年,2005年それぞれにアルバムをリリースする.

open.spotify.com

open.spotify.com

Wikipediaにも載っているバンドで,メンバーもプログレ界で有名な人が集まっている(らしい?).

新世界 (バンド) - Wikipedia

インティ・クリエイツ時代

ロックマン9と10のBGMを作曲している.

有名なのは下の二曲.

  • GALAXY FANTASY(ギャラクシーマンステージ)
  • WE'RE THE ROBOTS(ワイリーステージ2)

CDのみで配信は無いかもしれない.

ガスト時代

アトリエシリーズの「アーシャのアトリエ」や「エスカ&ロジーのアトリエ」などのBGMを作曲.

有名なのはこのあたり.

open.spotify.com

open.spotify.com

open.spotify.com

「蜂群崩壊症候群 -Colony Collapse Disorder-」はラスボスのBGMで,杉並児童合唱団による合唱が特徴的.

歌詞もすごい.

www.kasi-time.com

フリー時代

その後フリーになり,8BIT MUSIC POWERという作品の楽曲提供・マスタリングなどを行った.

8BIT MUSIC POWER FINAL - RIKI collection -

8BIT MUSIC POWER FINAL - RIKI collection -

その他では,過去に作成した楽曲を自分で歌うというアルバムをリリースしている.

open.spotify.com

ZUNTATA加入

2017年6月に行われたライブで,初ライブおよび加入が発表された.

www.taito.co.jp

ライブ後は,ダライアスやレイシリーズのアレンジを行ったり,スマホ版たけしの挑戦状の新規BGMを作成.

グルーヴコースターという音ゲーではFM音源でプログレな曲も提供.

iTunes等で購入可能.

FM音源黙示録-Apocalypse of FM Tone Generator-

FM音源黙示録-Apocalypse of FM Tone Generator-

  • Yu Shimoda (ZUNTATA)
  • サウンドトラック
  • ¥150
  • provided courtesy of iTunes

生きててよかった

宣伝

twitter.com

Spotifyでプレイリストを作成したのでお使いください.

open.spotify.com

楽曲のコレクション今はこんな感じ.

AWS CDKでmackerel-container-agentを同梱したECSタスク定義を作成する

AWS CDKからmackerel-container-agentをサイドカーにしたタスク定義を作成したいことがよくあるので,ライブラリを継承してmackerel-container-agentを必ず同梱するようなタスク定義クラスを作ってみた.

コードは以下.

import * as cdk from '@aws-cdk/cdk'
import * as ecs from '@aws-cdk/aws-ecs'

export interface Ec2TaskDefWithMackerelProps extends ecs.Ec2TaskDefinitionProps {
  mackerelRoles: string
  mackerelApiKey?: string
}

export class Ec2TaskDefWithMackerel extends ecs.Ec2TaskDefinition {
  constructor(scope: cdk.Construct, id: string, props: Ec2TaskDefWithMackerelProps) {
    super(scope, id, props)

    const platform = this.networkMode === ecs.NetworkMode.AwsVpc
      ? 'ecs_awsvpc'
      : 'ecs'

    const mackerelContainer = this.addContainer('mackerel-container-agent', {
      image: new ecs.DockerHubImage('mackerel/mackerel-container-agent:latest'),
      environment: {
        MACKEREL_CONTAINER_PLATFORM: platform,
        MACKEREL_ROLES: props.mackerelRoles,
        MACKEREL_APIKEY: props.mackerelApiKey || 'YOUR_API_KEY',
      },
      memoryLimitMiB: 128,
    })

    if (this.networkMode !== ecs.NetworkMode.AwsVpc) {
      this.addVolume({
        name: 'cgroup',
        host: {
          sourcePath: '/cgroup',
          // or Amazon Linux 2
          // sourcePath: '/sys/fs/cgroup', 
        },
      })

      this.addVolume({
        name: 'docker_sock',
        host: {
          sourcePath: '/var/run/docker.sock',
        },
      })

      mackerelContainer.addMountPoints(
        {
          containerPath: '/host/sys/fs/cgroup',
          sourceVolume: 'cgroup',
          readOnly: true,
        },
        {
          containerPath: '/var/run/docker.sock',
          sourceVolume: 'docker_sock',
          readOnly: true,
        },
      )
    }

    this.defaultContainer = undefined
  }
}

現状はEC2の場合のみ対応していて,どのネットワークモードでも動作する.(デフォルトはBridgeモード)

const apiTaskDef = new Ec2TaskDefWithMackerel(this, 'ApiTaskDef', {
  mackerelRoles: 'sample:api'
})

mackerel-container-agentのドキュメントはこちら.

mackerel.io

余談

this.defaultContainer = undefined

この部分は,mackerel-container-agentがdefault containerとしてセットされるのを防いでいる.

default containerはALBがタスクにアクセスする際のコンテナ,つまり「Container to load balance(負荷分散用のコンテナ)」としてアクセスされるコンテナのこと.

これはAWS CDKの用語で,ドキュメントに説明がある.

https://awslabs.github.io/aws-cdk/refs/_aws-cdk_aws-ecs.html?highlight=defaultcontainer#@aws-cdk/aws-ecs.Ec2TaskDefinition.defaultContainer

The first essential container that is added to this task will become the default container. と書いてあるとおり,最初にessential: trueなコンテナが選ばれるという動作になっており,mackerel-container-agentが選ばれてしまうので回避が必要.

YAPC::Tokyo 2019 に参加して,OSSとコミュニティについて見つめ直した

面白そうだから参加してみようという気持ちで参加したのが今回のYAPC::Tokyo 2019だった.

Perlの話やプロジェクトの話など,面白い話がたくさん聞けたのだけど,その中でもYAPC::Tokyo 2019 はテーマの「報恩謝徳」に関係した話が印象深かった.

具体的にはOSSとコミュニティと恩についての話で,自分が聴いた中では下の三つの話があった.

songmu.github.io

自分のOSSとコミュニティへの付き合い方について,重ね合わせて考えてみる.

例えば自分はあまりGitHubでコードを書いているわけではない.キャリアの話においてもGitHubを活用という話もあり,負い目を感じている部分もあった.

それが今回のYAPCに参加して,誰もが最初は小さいものから作っていたという話もあり許された気分になったし,もっと言えば自信を持っていいんだなと感じた.id:Songmuさんの失敗談も勇気付けるきっかけになった.

他の人のOSSに関して,「利用しているだけでも貢献している」というのはたしかにそうだなと思った.

逆に考えて,自分がOSSに限らずプロダクトを作ったとして,周りに使ってもらうだけでも嬉しいなということを思い出した.

PRに関してもそうで,単に自分が困っているから変えるという程度でPRを貰ったら嬉しいと思うし,自分もしていきたい.

「自分が困っているからPRを作る,自分でも変更できる内容ものだったからPRする」という気持ちで良いんだと思う.変に最初から世界を良くしようとか考えなくていいし,取り込むかどうか判断するのは自分ではなくコミッタなのだから.

ただ,自分を卑下しているような人にとっては特に,貢献内容の凄さ=修正の大変さと考えがちなのかもしれない.「自分でも変えられる」と言うことは一般的にすごいことではないのだろうと思ってしまう.

それに関連する話で,前夜祭では最近やっているAWS CDKについてLTをした.

AWS CDKは知名度が低く,使ってる人も全然知らないし,日本人のコントリビュータも全然いないという動機から発表した.

AWS CDKを使っている人に懇親会の場でコントリビュートの内容を伝えたところ「すげぇ!」と言われた場面があった.

修正量は別に大したことはないのだけれど,実際に便利になっているということが実感できた.

また,ただ利用者を増やしたいというだけで発表したのだけれど,結果的にOSSやコミュニティへの貢献になっていると気づいた.

自分のことを振り返ってみると本当に多くの情報をコミュニティから貰って,ここまで成長できたと思っている.

OSSやコミュニティを,ただ利用するだけで何も返せなかった自分が,こうやってコントリビュートや登壇で恩返しできるまでになったことは成長を感じている.

まだ駆け出しだけれど,OSSやコミュニティに貰った恩を再確認して,引続き恩を返していきたい.

そして,もっと世界が良くしていきたい.

伝えるための文章を作るのは難しいなと言う話

プログラムは継続的な改善が可能だが,文章は難しい.

例えばプログラミングをしてプロトタイプを作ってそれを伝えるときに,「このコードのこういう問題点は把握していて,今後改善する予定」と書くことはできる.

文章自体だとそうも行かなくて,メタ的に「下の文章は今こういう問題点がありますが後で直します」なんて書くことはできない.

自分はコードを書くのがそんなに遅いわけではないけれど,文章に関しては遅いと思っている問題がある.

なので,できる限り文章を書くスピードを上げるために,前提部分を高めに仮定して本当に伝えたい部分に直接必要な部分だけを書くということをよくやっている.

でも実際の前提部分が足りていないと一気に伝えることが不可能になってしまうし,コミュニケーション不足による追加の手間が発生してしまう.

そうして追加情報が必要になったとしても,情報が更新されたということを発信したり,別の場所に書くにしても情報の分断が発生する.

なので一発で伝わるようにできるのが一番ではある.

「伝えたい人を想定して,その人がどうなっていて欲しいかを目標にする」というアドバイスを目にしたのもあり,相手のことを考えてちゃんと書かないとなぁという気持ちになった.

直近だとエンジニアセミナーへの登壇もあるので,ここから改善していきたい.

hatena.connpass.com