Terraform と GItHub Actions で DigitalOcean Droplets の CI/CD を作る

VPS は DigitalOcean の Droplets が安いのでたまに利用しています。

www.digitalocean.com

Terraform は DigitalOcean に対応していて専用のプラグインが HashiCorp から提供されています。

www.terraform.io

Terraform 用の GitHub Actions も公開されていました。

GitHub - hashicorp/terraform-github-actions: Terraform GitHub Actions

Droplet は Web 画面をポチポチして作るのも簡単ですが、Terraform の勉強を兼ねて Actions で CI/CD することにしました。

Droplet を作る tf ファイル。5$ / mo のマシンを指定しています。DigitalOcean プロバイダーを定義しておくと、terraform init 実行時に必要なプラグインをダウンロードしてくれます。API トークンは環境変数 DIGITALOCEAN_TOKEN に展開しておきます。

provider "digitalocean" {
  # export DIGITALOCEAN_TOKEN="Your API TOKEN"
}

data "digitalocean_ssh_key" "ssh_key" {
  name = "blink"
}

resource "digitalocean_droplet" "dev" {
  image = "${var.ubuntu}"
  name = "dev-01"
  region = "${var.do_sgp1}"
  size = "s-1vcpu-1gb"
  ssh_keys = [data.digitalocean_ssh_key.ssh_key.id]
}

リージョンや OS は変数用の tf ファイルに書いて参照しています。

# Datacenter regions
variable "do_sgp1" {
  description = "Digital Ocean Singapore Data Center 1"
  default     = "sgp1"
}

# OS
variable "ubuntu" {
  description = "Eoan Ermine"
  default     = "ubuntu-19-10-x64"
}

GitHub Actions のワークフロー定義。PR 作成時に tf ファイルを検証して plan を出力、レビューできるようにします。

各 step で terraform のサブコマンド、init / validate / plan を実行しています。PR を編集するための GitHub アクセストークンと、DigitalOcean の API トークンは Secrets に格納して環境変数に渡しています。

name: Terraform Plan for droplet

on:
  pull_request:
    types: [opened]

jobs:
  terraform:
    name: 'Terraform'
    runs-on: ubuntu-latest
    steps:
      - name: 'Checkout'
        uses: actions/checkout@master
      - name: 'Terraform Init'
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.15
          tf_actions_subcommand: 'init'
          tf_actions_working_dir: 'droplet'
          tf_actions_comment: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TF_TOKEN }}
          DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
      - name: 'Terraform Validate'
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.15
          tf_actions_subcommand: 'validate'
          tf_actions_working_dir: 'droplet'
          tf_actions_comment: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TF_TOKEN }}
          DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
      - name: 'Terraform Plan'
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.15
          tf_actions_subcommand: 'plan'
          tf_actions_working_dir: 'droplet'
          tf_actions_comment: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TF_TOKEN }}
          DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}

この状態で branch を作成し tf ファイルを更新して PR を作成すると、ワークフローが実行され PR の画面で実行結果をレビューすることができます。

f:id:kondoumh:20191119215754p:plain

plan の結果も表示できます。

f:id:kondoumh:20191119215828p:plain

PR がマージされる時に実行するワークフローです。init の後続でサブコマンド apply を指定しているのと、PR がマージされたかどうか (github.event.pull_request.merged == true) を判定する if を入れています。

name: Terraform Apply droplet

on:
  pull_request:
    types: [closed]

jobs:
  terraform:
    name: 'Terraform'
    runs-on: ubuntu-latest
    steps:
      - name: 'Checkout'
        uses: actions/checkout@master
      - name: 'Terraform Init'
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.15
          tf_actions_subcommand: 'init'
          tf_actions_working_dir: 'droplet'
          tf_actions_comment: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TF_TOKEN }}
          DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
      - name: 'Terraform Apply'
        if: github.event.pull_request.merged == true
        uses: hashicorp/terraform-github-actions@master
        with:
          tf_actions_version: 0.12.15
          tf_actions_subcommand: 'apply'
          tf_actions_working_dir: 'droplet'
          tf_actions_comment: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TF_TOKEN }}
          DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}

PR をマージするとワークフローが実行されました。

f:id:kondoumh:20191119222408p:plain

そして無事 Droplet が作成されました。

f:id:kondoumh:20191119222440p:plain

文字通り Infrastructure as Code / GitOps を地で行くようなワークフローです。

単体の Droplet 作成には羊頭狗肉感は否めませんが、業務で AWS の複雑な依存関係を持つリソースを Terraform で作っているような場合にはかなり役立ちそうです。

ChangeLog メモが Emacs に回帰

ChangeLog メモ書きをかなり前に Emacs から VS Code に移行しました。

blog.kondoumh.com

自分用に VS Code 拡張も作ってました。

blog.kondoumh.com

自宅で MacBook 使う時はデスクトップの片隅に ChangeLog メモ用 VS Code が常駐してます。コード書き用の VS Code が常に数個起動してるので、ChangeLog メモ用環境は分離したくなってきました。

今年のはじめに Rust 環境を Emacs で構築した時にかなり設定をアップデートしてました。

blog.kondoumh.com

  • パッケージの使用宣言を require から use-package
  • 補完機能を auto-complete から company に
  • サーチを Anything から counsel に

メモ書きはやっぱり Emacs に戻そうと思ったら CUI 版しか入ってないことに気付きました。ターミナルも常に起動しっぱなしなので GUI 版を使ってターミナルとも分離したいところです。Homebrew で導入する際に brew install emacs だとターミナル版が入るようです。ということで、

% brew cask install emacs

これで GUI 版が入ります。

元々 ChangeLog 用環境がビルドインだし、自分用 elisp も書いていたので戻るのは簡単でした。さらに auto-complete や counsel がかなり賢く入力を補助してくれるのでメモ書きも楽になっています。

テーマは misterioso、フォントは Menlo 14pt に設定してみました。

f:id:kondoumh:20191110080403p:plain

ところで、ChangeLog じゃないテキスト作成には最近 Kibela を一人プロジェクトで使ってます。

kibe.la

Slack の自分専用チャンネルに書いてたこともあったのですが、Kibela は Markdown で書けるのと Windows / macOS / iOS / Android の各プラットフォームで PWA として専用アプリのように動作するところが便利です。コードスニペットや ToDo リストの管理もできます。ただ、ちょっと動作がバギーなところがあって長い文章には適してない気がしてます。

macOS Catalina にアップデート - Zsh にスイッチ

年末も近いし32bit アプリも使ってないし、そろそろいいかなと思って MacBook Pro Early 2015 でアップデートしました。

40分ほどで起動してきました。BetterTouchTool や Karabiner-Elements などでパーミッションの許可が必要でしたが問題なく使えるようになりました。Mojave の時は非 Retina ディスプレイのフォントレンダリングがちょっと話題になってましたが、設定を引き継いでいるからか問題ないように見えます。

Night Shift と外観モード

iOS 13と同様、Night Shift の設定に合わせてダークモードとライトモードを切り替える機能が実装されてました。久々のライトモード、明るいうちは悪くありません。日没後はダークになってくれます。この機能 Android にも実装されて欲しいところです。

f:id:kondoumh:20191109115519p:plain

Bash から Zsh へ

ターミナルを起動すると zsh がデフォルトになったよとメッセージが。

f:id:kondoumh:20191109115750p:plain

これまでも zsh は使おうと思えば使えましたが、bash が標準だし会社でも bash だしということで敬遠していました。せっかく macOS では zsh が標準となったのでメッセージに従って zsh に切り替えます。

ターミナル再起動して bash の path 設定などを .zshenv にコピー。oh-my-zsh も入れてみました。

% curl -L https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh | sh

oh-my-zsh ではデフォルトで Git のプラグインが有効になっていて、Git リポジトリ内ではブランチ名の表示や Git コマンド補完もしてくれます。Powerline フォント入れて、agnoster テーマを有効にしてみました。いい感じです。

f:id:kondoumh:20191109153537p:plain

Kubernetes 用のプラグインもあるようなので、複数のクラスターを切り替えて kubectl コマンドを叩く場合など、オペミス防止のためにも使いたいところです。

VS Code の統合ターミナルは bash のままだったので、settings.json に設定を直書きしました。

{
    "terminal.integrated.shell.osx": "/bin/zsh",
    "terminal.integrated.fontFamily": "Noto Mono for Powerline",
    "terminal.integrated.fontSize": 14
}

f:id:kondoumh:20191109175542p:plain

VMware Fusion アップデート

VMware Fusion は High Sierra の時からアップデートしておらず、v10 を使い続けていたのですが、Catalina では仮想マシンの画面が表示されなくなってしまいました。ということで2年ぶりのお布施。使用頻度が落ちているとはいえたまに使うことがあるので。

f:id:kondoumh:20191109135645p:plain

Sidecar

iPad をセカンドディスプレイにする Sidecar を試そうと思ったら、MacBook Pro は 2016年以降のモデルが必要。iPad Air 2nd gen も対応していないことが判明しました。Duet もすぐ使わなくなったのであまり使わなそうですがちょっと残念。

https://support.apple.com/ja-jp/HT210380#systemrequirements

ということで、今年の OS アップデート作業完了です。

野良 Scrapbox アプリ - ヒストリ機能とタブ幅調整

開いたページのヒストリ機能を追加しました。

f:id:kondoumh:20191109065744p:plain

f:id:kondoumh:20191109065814p:plain

ただこの機能ちょっと問題があって、Scrapbox ではタイトルの編集で URL が変わり WebView のイベント ("load-commit") が emit されてしまうので、編集途中のタイトルまで履歴に残ってしまいます。履歴にゴミを入れないようにする方法が思いつきませんでした。

2019.11.13 追記) ページの ID でユニーク化することで履歴のゴミが増えないように対応しました。

あと、これまでは長いタイトルの場合も全て表示していましたが、一定の幅で切り詰めるようにしました。データとしては持っているので、ツールチップでは全ての文字が表示されます。

f:id:kondoumh:20191109070205p:plain

Release v1.3.0 · kondoumh/sbe · GitHub

開発用 Kubernetes 環境構築ツールの比較

Kubernetes は GKE / EKS / AKS などで提供されているマネージドなサービスを使うのが楽ですが、課金もありますし開発時はローカルの環境が欲しくなります。

シングルノード構成のツールはオートスケーリングなどの機能が使えないという制約はあるものの、アプリの開発・動作確認環境としては十分使えます。マルチノード構成可能なツールもあります。

メジャーと思われるツールを比較してみました。

Docker Desktop

Docker Desktop for Mac and Windows | Docker

macOS と Windows で提供されている Docker を GUI で導入可能なソフトウェア。Docker が主で Kubernetes はオプションで有効化することで利用可能です。

macOS の場合は HyperKit が、Windows の場合は Hyper-V がノード用の仮想マシンとして使われます。Windows では VirtualBox との共存ができないという問題がありましたが、VirtualBox 6.0 以降 Hyper-V 対応されたので解消されていくものと思われます。

リリースごとに Kubernetes バージョンも上がっていきます。

Minikube

GitHub - kubernetes/minikube: Run Kubernetes locally

定番のローカル Kubernetes 環境です。ノードの仮想マシンとして HyperVisor を利用可能な他、VirtualBox や Docker を指定することもできます。

blog.kondoumh.com

kubeadm を内部的に利用しているため、Kubernetes バージョンの設定も可能です。

Dashboard や EFK など多くの機能がアドオンとして有効化可能です。

Addons | minikube

Windows / macOS / Linux 全てのプラットフォームをサポートしています。

MicroK8s

MicroK8s - Fast, Light, Upstream Developer Kubernetes

Ubuntu の Canonical が提供する Kubernetes パッケージ。APT ではなく Snap パッケージとして、Ubuntu 以外の Linux ディストリビューションでも利用可能です。

KVM などの HpyerVisor は利用していません。

microk8s.kubectl などコマンドにプレフィクスが付いていますが、snap alias microk8s.kubectl kubectl と snap コマンドで alias 指定すれば標準コマンドと同じように使えます。

アドオンで多くのパッケージが簡単に利用できるようになっています。

MicroK8s Addons | MicroK8s

macOS / Windows では Multipass で仮想マシンを使って動かす方法がガイドされています。

Multipass - Orchestrates virtual Ubuntu instances

インストールオプションで kubernetes バージョンを指定可能です。Minikube のようにクラスター作成時に指定はできないのですが、インストール・アンインストールが簡単なので、あまり環境を切り替える必要がないのであれば十分でしょう。

マルチノードにも対応しています(自前で MicroK8s をインストールしたマシンか VM を用意する必要があります)。

Multi-node MicroK8s | MicroK8s

Ubuntu 19.10 では MicroK8s のサポートが厚くなり、セキュア環境構築が楽になる他エッジ環境でも動作するようになるようです。

Ubuntu 19.10 delivers Kubernetes at the edge, multi-cloud infrastructure economics and an integrated AI/ML developer experience | Ubuntu

開発環境だけでなく実行環境としても普及を目指しているようです。当然 WSL2 でもサポートされると思われるので、今後ユーザーが増えていくかもしれません。

kind

GitHub - kubernetes-sigs/kind: Kubernetes IN Docker - local clusters for testing Kubernetes

Docker コンテナをノードとして利用し、マルチノードの環境を簡単に構築できることが特徴です。この特性を活かして CI 環境でマルチノードでしかできないテストケースを実行することもできます。マルチノードの指定は起動オプションで簡単にできます。

内部的に kubeadm を利用しているので、Kubernetes バージョンの指定も可能です。

blog.kondoumh.com

Windows / macOS / Linux 全てサポートしているのに加え、kind は積極的に WSL2 対応をしています。

まとめ

以上、各ツールの特徴でした。最後に比較表です。

Docker Desktop Minikube MicroK8s kind
Use HyperVisor
Select K8s version △※1
Multi node △※2
Support addons
Linux
Windows △※3
macOS △※3
  • ※1:インストール時のみ可能
  • ※2:Worker ノードの事前準備が必要
  • ※3:Multipass で利用可能

個人的には Docker Desktop と Minikube を併用し、Docker Desktop の Kubernetes は無効化しておくのが使いやすいかなと思っています。

野良 Scrapbox アプリ - Vuetify 2 の v-data-table への移行

野良 Scrapbox アプリのページ一覧画面では Vuetify の Data table component を使っています。

f:id:kondoumh:20191027100402p:plain

Vuetify は v1 → v2 でかなり breaking change が入りました。

https://github.com/vuetifyjs/vuetify/releases/tag/v2.0.0#user-content-upgrade-guide

数ヶ月 v1 のまま放置してましたが、やっとv2 に移行しました。

Apply vuetify 2 v-data-table · kondoumh/sbe@5fbaf09 · GitHub

  • :pagination 属性が廃止され、:options で指定するようになった
  • v-pagination コンポーネント(上部に配置してるページャー部品) との接続方法が変わった
  • ヘッダーのテンプレートが列単位の指定に
  • Vuetify モジュールの初期化方法が変わった
  • サーバーサイドのデータ件数が :total-items から :server-items-length
  • サーバーにリクエストを投げる時は、options の状態を取得してパラメータを組み立てるスタイルに
  • CSS のクラス名が table.v-table から .vdata-table に

と、色々変わってました。

Vue 本体も 3系では色々と変わるみたいですが。

github.com

ところで、Electron は 7.0.0 で OS の外観モード(ダーク、ライト)に合わせてモードが変わるようになりました。

Electron 7.0.0 | Electron Blog

ということで Electron 7.0.0 へのアップデートに合わせて、一覧画面でも OS がダークモードだったら Dark theme を適用するようにしてみました。

f:id:kondoumh:20191027093021p:plain

Release v1.2.0 · kondoumh/sbe · GitHub

Theia (VS Code ベース Web IDE) as a Service の Gitpod を使う

最近になって Gitpod を知りました。

www.gitpod.io

知ったきっかけは VS Code オンライン版の code-server を VPS などで自前で構築している人たちの記事を読んだことでした。

github.com

code-server は Digital Ocean の Droplet を使ってワンクリックでデプロイできるようになっていますが、ホスティングサービスは見当たりません*1。必要時にだけ利用できるセキュアな環境を構築するのは結構手間暇がかかるのでプロバイダーに任せたいと思いました。

VS Code ベースのオンライン IDE である Theia というのがあります。

theia-ide.org

Theia 自体をホスティングしているのが Gitpod です。 1ヶ月100時間まで無料で使えます(公開リポジトリのみ)。たまに個人開発で使う程度なら十分でしょう。

www.gitpod.io

ちなみに Theia は Eclipse Che 7 でも使われていました。

blog.kondoumh.com

Gitpod には Chrome 拡張が提供されていています。

chrome.google.com

この拡張をインストールすると GitHub リポジトリの Clone or download の右側に Gitpod ボタンが追加されるのでこれをポチっとするだけで、専用のワークスペースに展開してくれます。ラク過ぎてクラクラします。

f:id:kondoumh:20191020222609p:plain

ワークスペースにはちょっと前の世代の VS Code が再現されています。コード補完やターミナルなども問題なく使えます。

f:id:kondoumh:20191022021504p:plain

エディタの設定はアカウント共通のようですが、.theia/setting.json にワークスペース毎の設定を書くこともできます。

Java / Go / Python / C / C++ / Rust などの環境はインテグレートされているため、そのまま開発に入れる感じですが、Vue など特定フレームワーク用の VS Code 拡張は未導入なため vue ファイルのシンタックスハイライトなどが効いてません。

f:id:kondoumh:20191020232429p:plain

現時点では VS Code のように Marketplace を検索して拡張を追加することはできませんが、Marketplace をブラウザで開いて、Download Extension リンクから vsix 形式のファイルを取得してアップロードすればインストールができます。

f:id:kondoumh:20191020232554p:plain

Vue 用の拡張 vetur の vsix 形式のファイルをドラッグ&ドロップしてアップロード・インストールしてみました。

f:id:kondoumh:20191020232451p:plain

ちゃんと有効化されました。

f:id:kondoumh:20191020232507p:plain

シンタックスハイライトも効いてます。

f:id:kondoumh:20191020232525p:plain

VS Code 拡張を追加すると、プロジェクトルートに .gitpod.yml が追加され以下のような情報が出力されていました。

vscode:
  extensions:
    - octref.vetur@0.22.4:F5isQXjXpm5hcM6ONMslcA==

このファイルをコミットしておけば、新たにワークスペースを作り直した時も拡張がインストールされるのでしょう。

ところで、Vue などの Web アプリはターミナルで $ npm run serve で起動してプレビューすることができます*2

初期状態では、プレビューのブラウザに Invalid Host header というエラーが出てしまいます。そこで、vue.config.js に devServer の設定を追加します。

module.exports = {
    :
  devServer: {
    disableHostCheck: true
  }
}

これで正常にレンダリングされるようになりました。別ウィンドウに出せば、Chrome の DevTools も使えます。

f:id:kondoumh:20191022023059p:plain

VS Code は OS 機能との連携も重要で、ターミナルで使う CLI や Git CUI の Tig なども使いたくなります。NPM / pip / go module など言語のパッケージ管理システムでインストールするものはいいのですが、そうでないものはイメージのビルドプロセスに組み込むしかありません。

Gitpod は文字通り Kubernetes クラスターに配備される Pod なのでコンテナイメージのカスタマイズも可能です。

Gitpod - Docker Image

先ほどの .gitpod.yml に public なイメージを指定するか、独自 Dockerfile を指定することができます。

image:
  file: .gitpod.dockerfile

.gitpod.dockerfile では apt-get で Tig をインストールするよう記述してみました。

FROM gitpod/workspace-full:latest

USER root

RUN apt-get update && \
    apt-get install tig

これをリポジトリに commit / push してワークスペースを作り直すとイメージビルドが始まります。

f:id:kondoumh:20191022013641p:plain

エラーがなければビルドが終わりワークスペースが起動します。ターミナルで tig もちゃんと起動します。

f:id:kondoumh:20191022014402p:plain

2回目以降はビルドしたイメージが使われるので、通常のワークスペースと同じ時間で起動します。プロジェクト毎にイメージをビルドするのが面倒な場合、Docker Hub にイメージを置いて使うとよいでしょう*3。あるいは代替となる VS Code 拡張を探すのもありかもしれません。

ちなみに .gitpod.yml には、コンテナ起動時に実行したい task を登録しておくことができます。Gitpod で起動された環境のタイムゾーンは UTC になっており、git commit した時のタイムスタンプが日本とはずれたりします。そこで以下のようにタイムゾーンを設定するコマンドを実行するようにしてみました。

tasks:
  - command: export TZ="Asia/Tokyo"

以上、ざっくり GItpod を使ってみました。拡張がワークスペース単位だったりしてデスクトップで最新の VS Code を使っている感じとはちょっと違いますが、Eclipse Che や CodeSandbox よりも VS Code 成分高めだし、このレベルの開発環境がほぼ制限なく利用できるというのはすごいです。

現時点では PWA に対応していないのでデスクトップアプリのように使うには Electron などを使うことになります。あと、iPadOS の Safari でもちゃんと使えたということも記しておきます。

f:id:kondoumh:20191022102359p:plain

*1:以前は Coder.com でホスティングされていた模様です。

*2:ローカルサーバーを起動した時にポートを expose するかというポップアップが出ます。

*3:イメージのメンテナンスが必要になりますが。