フルリモート時代に対応するための開発環境におけるクラウドコンピューティング

はじめに

タイトルはカッコよくしてみましたが、話はよくあるEC2で開発環境を作るってやつです。 ここ半年ぐらい運用しているのですが、大きなトラブルなく運用できています。 特に最近の外出できない事態において、本当に半年前にやっておいて良かったなぁと実感しています。

利点としては以下のようなことが挙げられます。

  1. コンピューティングリソースはクラウドで割り当てるので、新規の開発者に物理マシンを支給する必要がない(少なくとも高価なものはないです。支給の必要がある場合にはうちの会社ではChromeOSを支給しています)
  2. 全てのソースコードクラウド上で管理されるので、物理的な事故によるセキュリティの心配がなくなる
  3. 何かトラブルがあった時に熟練した開発者が物理的に隣にいなくても、リモートから調査できる

おまけ tmuxセッションでペアプロもできる

これについて書いていきますが、基本的にはWebアプリケーション開発における話だと思ってください。

コンピューティングリソースはクラウドで割り当てるので、新規の開発者に物理マシンを支給する必要がない

これに関しては割安かどうかは会社によるかもしれません。うちはt3a.xlargeを各自に割り当てています。 シンガポールリージョンで1時間0.1888USDなので、単純計算で一日付けっ放しにしたとすると1ヶ月で、 0.1888 * 24 * 30 = 135.936USD ですね。

ただ普通のプロダクトでt3.xlargeは必要ないかなぁという気もします。 僕たちの開発環境はk8sをプロダクションとほぼ同様の環境で(リソース的に同様ということではなく、構成は同様という意味で)動かしているので、通常の開発環境のWebアプリケーションよりはリソースを使っています。

僕の使ってるローカルのマシンはもう相当ガタがきているので、これをストレスなく動かせる自信がないです。これもクラウドにして良かったなーと思う一つの理由ですね。

あとはスクリプトを組んで、ちゃんと使ってない時間は落とすようにすれば経費は大分削減できると思います。 単純計算で一日に8時間労働するとすると、1/3になるので。(週末や土日は計算がめんどいの省く)

全てのソースコードクラウド上で管理されるので、物理的な事故によるセキュリティの心配がなくなる

外出時にマシンを落としたりした時にリモートでロックかけなきゃ!みたいな話はよく聞きますが、ローカルにデータは落とさないという制約さえ守っていればもうその心配はなくなります。 ただ公開鍵を開発環境のマシンから削除すればいいだけです。 自分自身でも開発していて、特にアプリケーションのソースコードをローカルに落とす必要は感じないです。

何かトラブルがあった時に熟練した開発者が物理的に隣にいなくても、リモートから調査できる

フルリモートにおいて、これはすごく助かっています。 日々成長、変化していくプロダクションコードにおいて「xxを最新にあげたら動かなくなった!」みたいな悲鳴はよく聞きます。 その度に詳しい開発者が隣に行って調査して解決する、みたいなのはよく見られる光景です。

物理的に近い距離にいればそんなに苦ではないですが、フルリモートではそれも難しいです。何らかのオンラインミーティングサービスを使えばスクリーンシェア機能を通じてある程度近いことはできると思いますが、それでも簡単ではないでしょう。

この環境を整備しておけば、sshで他人の開発環境に入って容易に調査することができます。 前述のおまけのところに書きましたが、tmuxセッションを使ってペアプロもできます。

前置きが長くなりましたが、構築のコツや運用などまとめておこうかなーと思います。

構築

stepサーバを立てる

めちゃめちゃ安いサーバでいいと思うので、各開発環境へのステップサーバとして立ち上げておくと便利です。 このサーバを各開発環境へのセットアップスクリプトの流し込みや、/etc/hosts を通じてのローカルマシンからリモートマシンへのアクセスのアドレスの解決に使います。(詳しくは後述します)

セットアップに関しては、僕たちはansibleを使ってスクリプトを組んでいます。新しい開発者が入ってきたら、スクリプトを流して待つだけで新しい開発環境が出来上がります。

EC2インスタンスを立てる

stepサーバと同じVPCを設定して、private ipをstepサーバから解決できるようにしておきます。

それ以外は特別なことはないのですが、開発マシンに一様に割り当てるIAMロールのセットアップをしておくと良いです。 それによって、そのロールの権限を変えることでAWSリソースへのアクセスを制限できるので、各開発者がリモートマシンに自身のAWSのcredentialをセットアップする必要がありません。

僕たちはAWS SSMのparameter storeを使って環境変数などを管理していますが、各開発環境からのアクセスもロールを通じてこの値を取ることができます。

AWS Systems Manager Parameter Store - AWS Systems Manager

環境変数の管理方法は色々あると思いますが、プロダクションでAWSを使っているなら、このあたりもAWSに寄せておくと便利に使えていいですね。

stepサーバのhostsの登録

ansibleを使っているなら、スクリプトを流すために開発環境のアドレスをansibleのhostsファイルに書いておくと思います。

[dev_machines]
joe_re1.dev ansible_host=172.0.0.1
joe_re2.dev ansible_host=172.0.0.2
joe_re3.dev ansible_host=172.0.0.3

おそらく誰がやってもこんな感じでしょう。ホスト名はなんでもいいのでsshの時に使いたい名前を指定してください。ansible_host=の右辺はEC2のprivate ipアドレスになります。

ssh時にここで設定したマシン名を使えるようにする為、これを元にstepサーバの/etc/hostsを生成します。これもansibleスクリプトで行なっているので、向き先が自分(127.0.0.1)のスクリプトを各開発マシンに実行するものとは別に用意しています。

冪等性を保つため、最初のステップ(set default host)でからのファイルを作成、2つめのstep(Add the inventory into /etc/hosts)でansibleのhostsから/etc/hostsの更新を行なっています。

  - name: set default host
    copy:
      src: ../resources/dev_step_settings/hosts
      dest: /etc/hosts

  - name: Add the inventory into /etc/hosts
    lineinfile:
      dest: /etc/hosts
      regexp: '.*{{ item }}$'
      line: "{{ hostvars[item]['ansible_host'] }} {{item}}"
      state: present
    when: hostvars[item]['ansible_host'] is defined
    with_items:
      - "{{ groups['dev_machines'] }}"

あんまりこれを詳しく説明しだすとansibleの説明になってしまうので省きます。気になる方はこちらが参考になると思います。

Using Variables — Ansible Documentation

シェルなどでも簡単に書ける処理だとは思うので、どんなプロビジョニングツールを使っていても大丈夫だと思います。

開発者からsshの公開鍵をもらう

もらった後にstepサーバと開発環境サーバの両方に公開鍵を登録しておきます。 ansibleではauthorized_keyを使って簡単に書けます。

authorized_key – Adds or removes an SSH authorized key — Ansible Documentation

セットアップスクリプトを開発環境サーバに流す

基本は待つだけです。自分たちがやっているのは、細かいところを省けばgithubリポジトリのクローン、docker containerのビルド、k8s(microk8s)のセットアップ、開発に必要な環境変数の設定あたりです。

前述のように、awsリソースへのアクセスが必要なものはロールを通じて行います。

開発者側の設定

ssh config

以下のようなssh configの設定を開発者に追加してもらいます。

stepサーバへの設定

Host dev-step-server
  Hostname ec2-xxxxxxxxxxx.ap-southeast-1.compute.amazonaws.com
  User ubuntu
  Port 22
  IdentityFile ~/.ssh/id_rsa

開発マシンへの設定

Host joe_re.dev
  Hostname joe_re.dev
  User ubuntu
  Port 22
  ProxyCommand ssh dev-step-server -W %h:%p

stepサーバへの設定の部分は特に説明する部分はないですね。

開発マシンへの設定の方もインフラエンジニアの方なら定番かもしれませんが、ProxyCommandを使って、接続先のホストの解決をdev-step-serverに任せています。 -Wオプション以下の%hに本来の接続先のホストが、%pにポートが入ります。なのでこの場合、joe_re.dev:22となります。

joe_re.devの名前はstepサーバのhostsに登録済みなので、これを解決してリモートサーバにアクセスができます。

/etc/hosts

chrome.local ドメインのアクセスをlocalhostに自動でしてくれます。 メンバーの何人かはChromeOSを使っていますが、現在のChromeOSは/etc/hostsの設定を行うことができないように制限されているので基本的には.localドメインで開発をしています。 なのでChromeを使う限りにおいては /etc/hostsをいじる必要はありません。ただし、手元のシェルから何かしたいなーとか他のブラウザからアクセスしたいなーとかの場合は設定する必要があります。

port forwardingで開発環境のサーバにアクセス

Mac, Linux, WIndows

この手の話ではど定番のやつですね。他の方法があるなら知りたいです。

自分たちはk8sを開発環境で動かしているので、-Lオプションを使って、リモートの開発サーバをさらに経由してk8sのアドレスにアクセスしています。

ssh -F ~/.ssh/config -L 9001:10.152.183.218:443 joe_re.dev

Windowsだとsshするのにちょっとコツがいるのかもしれませんが、開発環境としては自分は使っていないこともあって、把握していないです。

ChromeOS

ChromeOSは少し特殊な設定が必要です。最新のChromeOSはターミナルのssh clientとブラウザと完全に独立しているので、ターミナルでport forwardingしてもブラウザからは開発環境にアクセスすることができません。 なのでChromeのエクステンションでこれを解決します。 chrome.google.com

設定はこんな感じです。 f:id:joe-re:20200518072625p:plain

このエクステンション上でProxyCommandをうまく噛ませる方法が分からずに、ここで今まで避けてたPublicDNSが登場しています。 悔しい。。どなたか設定方法ご存知の方は教えてください。

構築はここまでで完了です。

運用

sshを通じた開発

開発環境は開発者個人に割り当てられているものなので、配布したあとは自由にセットアップしてもらっています。仮に壊してもansible scriptをapplyするだけですぐに元に戻せます。

なのでvimemacsなどのターミナルフレンドリーなエディタを使っている人であれば、そのまま開発環境上にセットアップするだけです。 ホストのeditorを使う場合はVSCのRemoteSSHプラグインが便利です。

code.visualstudio.com

正直使う前はssh経由でホスト上のエディタで開発するとかエクスペリエンスそんなによくないんだろうな〜と思っていたのですが、使ってみるとめっちゃ快適です。 ほぼローカルと遜色なく開発できます。

トラブルシュート

冒頭に述べた話ですが、何か自分では解決できそうにない未知のエラーに遭遇した場合に、ごめんちょっと見てーってslackで問いかければ、詳しい人がリモートから直接調査することができます。

フルリモートの環境において、あれ見た?このコマンドの結果はどう?みたいなやり取りを省けるので便利です。

全ての開発環境に何か変更を加えたいとき

長く運用していると、あるタイミングで全ての開発環境に一斉に実行して欲しいコマンドがあったりします。アプリケーション側であれば、大体dockerfileに記述するので、最新化してリビルドしてってslackに書けばそれで終わるのですが、k8sのバージョンをあげた場合などに必要になったりすることが多いです。

そんな時はansible scriptを全台に向けて流すだけなので簡単です。次回以降のセットアップにも必要になるならそのまま残しておきましょう。

おわりに

そんなこんなで割と快適な環境で開発できています。 フルリモートを意識すると、物理的なマシンの管理にリソースを割かなくて済むのは非常にありがたいと思います。 まだまだ改善できるところもあると思うので、良いアイデアなどお持ちの方はぜひ教えてください。

シンガポールでの生活

ex freeeの@joe_reです。

裏freee developers Advent Calendar 2018の14日目の記事を書きます。

何を書こうか迷ったんですが、freeeをやめた後の近況報告も兼ねて、シンガポールでの生活を中心に書こうと思います。 (退職記事はこちら)

いつから、どういう形態でシンガポールにいるの

今年の10/1から住んでいます。なのでまだ2ヶ月と少しという感じです。

会社としては本社をシンガポールに置いていて、支社が日本にあります。

僕は日本支社から出向している日本人駐在員という形で就労ビザを取っています。

どこに住んでいるの

オーチャードとサマーセットの間に住んでいます。

ショッピングがしたい観光客向けの場所という感じで、日本で言うと銀座みたいな感じです。

これはサマーセット駅の駅ビルの入り口です。中に無数のお店があり、ウィンドウショッピングは無限に無料でできます。

f:id:joe-re:20181214153248p:plain

また、中にドンキホーテ(シンガポールでは商標権の問題でドンドンドンキに名前が変わっている)やTokyu handsがあります。 ドンキホーテは24時間空いていてクッソ便利です。値段も日本とそんなに変わりません。お酒以外は。 僕は行く度にここでカップラーメンを5,6個買って帰るルーチンに陥っています。

近くに高島屋伊勢丹などもあります。銀座ですね。

ブランドにあまり興味がないので特に何か買い物した記憶はありません。

今はクリスマスシーズンなのもあって、クリスマスイルミネーションでライトアップされていたり、夜な夜なライブやってたりして、週末の夜はめっちゃ賑わってます。 f:id:joe-re:20181214154742p:plain f:id:joe-re:20181214154804p:plain

物価

純粋な数値だけを見ると、シンガポールは物価の高い国ですが、住んでみると高くは感じないです。 もちろん日本も物価の高い国なので、他の国と比べるとまた違うとは思いますが。

この記事によると、東京が3位でシンガポールが5位だそうです。

物価の高い都市のベスト10にアジアが5都市、日本は何位? |ビジネス+IT

ただし、高いものと安いものははっきりと日本と違います。

交通機関は安い

シンガポールに来てまず驚いたのは、交通機関の安さです。 電車とバスなら、2.5シンガポールドル(今のレートでだいたい200円ぐらい)でほとんどの場所に行けます。 特にバスはクッソ安い。

タクシーも日本に比べるとめちゃめちゃ安いです。

僕の住んでいるところから空港まではだいたい20キロぐらいなのですが、時間帯にもよりますがだいたい20S$(1,600円)ぐらいで行けます。

シンガポールで今主要なライドシェアリングサービス(Uberみたいなやつ)はGrabです。 使い勝手が良くてポチるだけですぐに迎えに来てくれて、今のところトラブルはありません。

シンガポールに来た時は入れておくと便利です。

嗜好品は高い

反対に高いのは、酒などの嗜好品です。

もちろん税金が高いのと、これらは基本的に輸入品なのがあって、下手すると日本の3倍ぐらいしている場合もあります。 缶ビールでも1.5〜2倍ぐらいなイメージです。

生活に必要な交通機関は安く、反対に嗜好品が高いのはシンガポールの合理的な部分を強く反映している部分だと思います。

酒が高いことに起因する1つのクソみたいなエピソードがあるのですが、思い返してみたら本当にクソみたいな話だったし面白い気もしなかったので割愛します。 酒の肴にでもしますので飲みに行きましょう。

食事はものによる

食事は、贅沢しようと思えば高いし、安く済ませようと思えばいくらでも安く済ませられます。

観光客向けの食事や日本食は高いですが、ローカルフードならだいたい5S$〜8S$ぐらいで満足できます。

東京に住んでいる人からすれば逆に安いのではないでしょうか。

シンガポールには、ローカルの人のメジャーな食事処としてホーカー(hawker)と呼ばれる屋台形式のお店が集まった場所がたくさんあります。 活気のある場所が多く、競争があるのでハズレのお店は少ないと思います。 ローカルフードを安価に楽しみたいならすごくおすすめです。

写真はセラングーンのhawkerで頼んだお粥料理です。 f:id:joe-re:20181214172534p:plain

家賃は高い

家賃に関して具体的な金額までは詳しく知りませんが、基本的には高いと思います。 こちらでは結婚して子供ができるまでは、ルームシェアする人が多いみたいです。 僕は場所の関係もあってとても一人で払える金額ではないので、会社の補助 + 同僚と3人でルームシェアという形でコンドミニアムに住んでいます。

住居

前述の通り、同僚と3人でルームシェアをしています。間取り的には多分3LDKって感じです。

これはリビング f:id:joe-re:20181214173933p:plain

キッチン f:id:joe-re:20181214174334p:plain

部屋 f:id:joe-re:20181214173959p:plain

10Fに住んでいます。眺めはこんな感じです。 f:id:joe-re:20181214174417p:plain

共有部にはBBQスペースやプールもあります。プールには一度も入っていません。入りたいとは思っています。 f:id:joe-re:20181214174705p:plain

f:id:joe-re:20181214174729p:plain

既婚者は僕だけで、奥さんがたまに来るので、ありがたいことに一番広い部屋をもらっています。

1人や2人なら余裕で泊められるので、もしシンガポールで旅費を安く抑えたいなどの気持ちがある方はお声がけください。

食事

辛いものが多いですが、そればっかりってわけではないです。むしろ辛くないものの方が多分多いです。 ただ辛いものが好きな人は、何にでもチリソースをかけます。

配慮はされていて、勝手にチリソースかけられて出されるなんてことはあんまりと思います。 お店で何か頼んだ時にドゥーユーウォントチリ?みたいな感じで聞かれると思うので、辛いものが苦手な人はノーと言える日本人になりましょう。僕は辛いもの苦手なのに結構イェスって言ってます。

僕が最高に好きな朝食メニューにカヤトーストというものがあります。 f:id:joe-re:20181214175706p:plain

これはトーストにカヤジャムという、ココナッツミルクと卵とはちみつなどなどを混ぜ合わせた結構甘いジャムを挟んで、日本で言う所の温泉卵をかけつつ食べるみたいなメニューです。

言葉にすると全く美味しさが伝わらないと思いますが、僕がこれが好きすぎています。 家の近くにはヤクーンカヤトーストというお店とトーストボックスというお店があり、これがカヤトーストを食べられるお店としては(多分)有名です。4.5S$とかだったと思います。

非常に美味しいのでおすすめなのですが、これをローカルの友達に話した時には「俺のよく行く喫茶店なら2.5S$で食べられるし、なんなら自分で作るよ」と言われました。

まぁ多分日本で言う所のスターバックスみたいな感覚なんだと思います。自信はないです。

あまり日本で馴染みのない料理として、エイ(スティングレイ)があります。写真は撮り忘れました。 食べる前に想像していたような臭みはなくて、さらに思ったよりも歯ごたえがあって美味しかったです。

が、一緒に提供されていたチリソースは地獄のような辛さでした。

あとは土鍋(クレイポッド)料理もローカルなメジャー料理です。クッソうまいです。 f:id:joe-re:20181214182337p:plain

あと有名どころであるところのチキンライスは当然美味しいです。僕は蒸してあるパターンを好みます。 f:id:joe-re:20181214182535p:plain

交流

シンガポールにいてというよりは、海外に住んでみてということになると思いますが、趣味の大切さを特に感じました。

最初は日本からきたばっかりなので当然遊びに行く友達もおらず、一日中家にいることがほとんどでしたが、最近は趣味を通じて交流することが増えてきました。

僕の場合は、音楽(一応これでもギターをやってたりします)とボードゲームが主な趣味です。

もちろん現地の人と交流しようと思うと言語の壁はありますが(そして僕にとってそれは決して低くないですが)、共通の趣味や同じように興味を持っていることがあると格段にその敷居は下がるのを感じます。

勉強して言葉を喋れるようになることも大事ですが、それ以上に、自分が何に興味を持ち、何が好きで、何が嫌いで、何をしたいか、みたいな部分をしっかり持つのが大事だと思います。 音楽やってて良かったです。

話は変わって、シンガポールのカラオケに基本的に日本の歌はないですが場所を選べばあります。シンガポリアンで日本に興味がある人は日本のアニメをたくさんみている人が多いです。

f:id:joe-re:20181214185011p:plain

あと日本語バッキバキにできるシンガポール人と出会うと刺激になります。なんでこいつシンガポールにいてこんなに日本語喋れるんや。

仕事

長くなったので割愛します

終わり

年末、12/20〜12/30ぐらいまで日本にいます。飲みにでも行きましょう。お土産あげます。お願いします。

シンガポールに来る予定がある人もぜひお声がけください、案内します。

明日はmacha3162さんです。

kubernetesをローカルの開発に活用する

できる限りプロダクションのクラスタ設定をそのままローカルの開発にも使いたいなー、と思って色々と試行錯誤して、ようやく形になってきたので書いておく。

なぜローカルでkubernetesを動かしたいのか

最近ではInfrastructure as Code、Immutable Infrastructureの考え方と共に、コンテナの上でアプリケーションの環境の構築、運用、開発をすることが増えてきた。

少し前までは、Dockerでローカルの開発環境の構築は楽になったけど、本番にデプロイするのにはハードルがある印象が個人的にはあった。だけど、kubernetesの登場によってそのハードルは大きく下がった。

最近はマイクロサービスアーキテクチャへの注目と共に、様々なコンテナが協調してサービスを形作る構成が増えてきたように思う。kubernetesはこの全てのコンテナを管理する。

kubernetesは最初に学ばなければならないことは多いけれど、一度その概念を掴めばどれだけ楽に構成を管理できるか実感できる。

2年前ぐらい前のものだけど、全体の概念を掴むのはこの動画が良かった。

www.youtube.com

全ての設定はyamlで記述することになるので、構成管理がコード化できるところも良い。(ともすればyaml地獄とも揶揄されるけど)

複数のプロセスを立ち上げて開発をしている場合には、各プロセスを協調させるために、ローカル専用のプロキシサーバを立てるケースもある。

しかし各コンテナのインターナルな通信や、環境変数の設定をkubernetesに任せていると、これがローカルでそのまま動けばプロキシサーバなどいらずにプロダクションと同等の動作をさせることができるのでは、という気持ちになった。

ローカル開発とプロダクションとの差異を解決するためのkustomize

なるべくプロダクションの構成をそのまま使いたいとはいえ、どうしても差異はある。

そもそもプロダクションとローカルではデプロイするイメージは確実に違うし、Webアプリケーション開発においてはクライアントサイドのjsやhtmlなどの静的なファイルをビルドするためのサーバを立てなければいけなかったりもする。

この差異を解決するのには kustomize というツールを使うことにした。

kustomizeにより、環境ごとの差分のみを記述する

kustomizeを用いると、プロダクションの設定とローカルの設定は差分のみを記述するだけで済むようになる。 kustomizeが用意する基本的なレイヤーは、ベースとオーバレイの2つである。

各サービスの環境(プロダクション、ステージング、ローカルなど)ごとの設定は差分のみを記述した上でオーバレイのレイヤーに配置しておき、適用の際にベースの設定にパッチを当てる。

具体的には各環境にkustomization.yamlというファイルを用意し、そこがエントリポイントになる。

kustomizeのリポジトリのファイル配置の例を転記する。

~/someApp
├── base
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   └── service.yaml
└── overlays
    ├── development
    │   ├── cpu_count.yaml
    │   ├── kustomization.yaml
    │   └── replica_count.yaml
    └── production
        ├── cpu_count.yaml
        ├── kustomization.yaml
        └── replica_count.yaml

例えば、overlays/development/kustomization.yamlの内容は以下のようになるだろう。

namespace: dev-someApp
commonLabels:
  stage: development
bases:
  - ../base
resources:
  - cpu_count.yaml
  - replica_count.yaml

basesセクションに記述したものはdevelopment, productionの両方から参照され、その差分のあるファイルは各オーバレイのレイヤーにおいておく。 この例ではファイルごと変えているが、ファイルの中で部分的に差分を適用したい場合には、patchesというセクションを使えば可能だ。

patches:
  - patches/deployment.yaml

環境変数の管理

kubernetesを用いて環境変数を管理するには、SecretsとConfigMapを用いるのが一般的だ。 基本的に機密性の高い情報の管理にはSecrets、それ以外ではConfigMapを使う。

kubernetesを使うとリリースごとにリビジョンをつけることができるので、問題がおきた時にロールバックが容易になる。

しかし、リリースごとに環境変数を変えている場合にはこれもロールバックしなければいけないことになり、直接SecretsやConfigMapをいじってしまうと少し厄介になる。

これを解決するために、kustomizeにより作成されたSecret、ConfigMapにはそれぞれリソースに一意な名前となるようにサフィックスが自動で付与され、それを参照することになる。

つまり、デプロイするたびにSecretsやConfigMapは増えていく。

試しに見てみる。

$ kubectl get secrets -n dev-application
NAME                             TYPE                                  DATA      AGE
default-token-5lctz              kubernetes.io/service-account-token   3         1d
secrets-environment-4khckhf9c7   Opaque                                27        5h
secrets-environment-9hg6tc462d   Opaque                                29        3h
secrets-environment-bb4k2t7cd9   Opaque                                26        5h

kustomizeを利用しない場合にこの仕組みを実現する方法は、@yuyatさんの以下の記事が大変参考になった。

Kubernetes の ConfigMap を Immutable に管理する | Born Too Late

また、secretsGenerator、configMapGeneratorという仕組みも用意されていて、ここにはリテラルだけでなく、コマンドの出力結果も適用することができる。

僕は環境変数AWS SystemManagerのParameterStore(ssm)で管理しているので、以下のように記述している。(get_env_from_ssmはaws-cliをラップして、ssmから値を取り出して標準出力するだけの簡単なシェルスクリプトです。)

secretGenerator:
- name: server-environment
  commands:
    BAR_API_KEY: "../../scripts/get_env_from_ssm /dev/BAR_API_KEY"
    FOO_SECRET: "../../scripts/get_env_from_ssm /dev/FOO_SECRET"
  type: Opaque

ローカルで利用するソースコードのチェックアウトとイメージのビルド

ローカル環境のソースコードのパスは開発者ごとに違うのが普通だけど、後述のソースコードのコンテナへのマウントや、イメージの一括のビルドスクリプトを簡易にするため、今回は決められたパスに関連ソースコードをチェックアウトし、イメージをビルドするスクリプトを用意した。Dockerfileは各リポジトリに置いている。

工夫すればソースコードのパスは可変にはできると思う。けど結構苦労すると思う。

具体的には以下のようなスクリプトになった。

  • scripts/checkout_all
#! /bin/bash

mkdir -p ${HOME}/awesomeApps

echo "local setup start..."

if [ -d "${HOME}/awesomeApps/bar" ]; then
  echo "bar already exists."
else
  # git clone ...
fi

if [ -d "${HOME}/awesomeApps/foo" ]; then
  echo "foo already exists."
else
  # git clone
fi

# ...
# ...

echo "finished."
  • scripts/build_all_images
#! /bin/bash

docker build -t foo:dev ${HOME}/awesomeApps/foo
docker build -t bar:dev ${HOME}/awesomeApps/bar
# ...
# ...

開発用のbuildのイメージのタグをバージョン管理せずにdevのみで作っていると、Dockerfileに修正が発生した時に更新が少し面倒になる。

なので開発用のタグもバージョン管理した方が良いかもしれないけど、ローカルのソースコードのマウントのところで後述する通り、kubernetesyamlプログラマブルにするのは少し面倒なので、複雑性とのトレードオフになる。

人数が多くて変更が発生した際に周知が大変な場合には、バージョン管理する価値はあると思う。

ローカルのソースコードkubernetes上のコンテナにマウントする

kubernetesにはvolumesにhostPathを指定することができる。

Volumes - Kubernetes

これを用いればホストのソースコードをマウントすることは可能だが、ここは絶対パスで指定する必要があることに注意が必要だ。

さらにkubernetesはDeclarativeであることを崩さないため、templateの機能は提供されておらず、ここでhostの環境変数で設定を置き換えることはできない。

Feature: Support using environment variables inside deployment yaml file · Issue #52787 · kubernetes/kubernetes · GitHub

そこで、置き換えにはenvsubstを用いることにした。 具体的には以下のようなコマンドでデプロイすることになる。

kustomize build ./someApp/overlays/development/kustomization.yaml build | envsubst | kubectl apply -f -

別にenvsubstでなくても、置き換えられればいいだけなのでsedでも良い。 ここで1ステップ追加されてしまうのは僕の調べた限りでは回避できなかった。 具体的なDeploymentのファイルは以下のようになる。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    service: server
  name: server
spec:
  template:
    spec:
      volumes:
      - name: src
        hostPath:
          path: "${HOME}/awesomeApps/bar"
          type: DirectoryOrCreate
      containers:
      - name: server
        args:
        - yarn
        - run
        - dev
        image: bar:dev
        volumeMounts:
        - mountPath: /opt/app
          name: src
        workingDir: /opt/app

Macではminikubeではなくdocker-for-mackubernetesを使う

windowsの人はdocker-for-windowsになる。linuxの人はminikubeを使ったとしても、driverにVirtualBoxを使わなければ良い。

Macユーザなので試した訳ではないけど、以下の議論がある。

More documentation around vm-driver=none for local use · Issue #2575 · kubernetes/minikube · GitHub

MacでもVirtualBoxを使わなければいけるのかもしれない。

docsをみると、VirtualBoxの他にVMware Fusion, HyperKitの選択肢があるようだ。

Install Minikube - Kubernetes

VirtualBoxを用いると、ファイルシステムの違いにより、inotifyイベントを検知できないためファイルの変更の監視が難しい。 ファイルの変更を検知してビルドの必要がある場合などに、これは致命的だ。

github.com

docker-for-macは体感として少し遅いが、これは今後改善されていくと信じたい。

おわり

まだ構築したばっかりなので、これから問題は出るかもしれない。 とりあえず今の所は便利に開発することができている。 今回紹介していないところで、細かいtips的なものもあるので、またそれは今度書こうと思う。