GitHub Actions で AWS CDK
はじめに
AWS Advent Calendar 2019 - Qiita の 10日目への寄稿です。
AWS CDK が 2019年7月11日に、 GitHub Actions が 2019年11月14日にそれぞれ GAと なりました。 qiita.com のようにGitHub へクレデンシャルを登録しておけば、 GitHub Actions を使って CDK によるCloudFormation Stack の構築が出来るのでは無いか?と思い立ったので試してみました。 今回はPythonで記述してみようと思います。
環境構築
GitHub Actions では、Docker コンテナーを使うということで CDK 入りの軽量なコンテナーとなる Dockerfile を github.com 作りました。 そして、CDK を使って CloudFormatuon Stac kを構築するためのコードと、それを動かす GitHub Workflow は GitHub - poad/Advent に置いています。 リポジトリーを分けた方が理解しやすいこともあって分けています。
そもそも Action と Workflow って何?
GitHub Actions では、Action と呼ばれる機能を作成したり、既に用意されている Action を Workflow から呼び出して CI/CD を行います。
Action
後述する Workflow から呼び出して実行するための機能。 Docker コンテナー上で実行される。 action.yml で定義する。
Workflow
前述した Action をパラメーターと共に順に実行していく手順をYAMLで記述したもの。 .github/workflows/main.yml で定義する。
CodePipeline との比較
ざっくりとCodePipeline と比較してみます。
CodePipeline | GitHub Actions | |
---|---|---|
GitHub との親和性 | △ | ◎ |
AWS との親和性 | ◎ | △ |
単発実行 | ○ | × |
※ 上記評価はあくまでも個人的な主観です
GitHub との親和性
CodePipeline では、GitHub のリポジトリーとブランチしか指定出来ません。 一方、GitHub Actions では、リポジトリーとブランチの組み合わせ以外にも、リポジトリーとタグの組み合わせを指定できるほか、 push 以外を起動トリガーと出来ます。
AWS との親和性
当然ながら、CodePipeline であれば CloudFormation や ECS など、様々なサービスのデプロイを既存の Action として指定できます。 また、GitHub Actions はAWSのクレデンシャルを使用して AWS CLI や AWS CDK を使用します。 IAM ロールなどを絞りたい場合に専用の IAM ユーザーを作成して絞る必要があります。 一方、CodePipeline では、CodePipeline 自体やそこから呼び出す AWS のサービス向けの IAM ロールを CodePipeline 毎に作成・指定することが出来ます。
単発実行
GitHub Actions では、リポジトリーへの push などを行わないと実行できません。 同じコード、設定で 再デプロイしたい場合に実行する方法がなさそうです。
Action を作ってみる
実は、AWS CDK GitHub Actions · Actions · GitHub Marketplace · GitHub として既に CDK を使うための GitHub Actions があります。 そのまま使用すればいいのですが、それでは記事にならないどころか、必要となった場合に作り方が分からなくなります。
そこで、上記のActionを参考に自分で作ってみます。
Dockerfile
alpine:3
に npm
と python3
、pip
、awscli
、cdk
をインストールします。
entrypoint.sh として、CDK のコードで使用する Python module のインストールを行い、
workflow で指定された各サブコマンドを実行するシェルスクリプトを ENTRYPOINT とします。
action.yml
Action の定義を行います。
action.yml のシンタックスは Metadata syntax for GitHub Actions - GitHub Help
workflow を作る
.github/workflows/main.yml
を作ります。 main.yml
以外に YAML ファイルを置いた場合にどう動くのかは試してません。
先述したとおり、ビルドやデプロイなど、どういった作業の流れなのかを定義したファイルです。
その名の通りですね。
ちなみに、シンタックスは Workflow syntax for GitHub Actions - GitHub Help
step が CodePipeline の Actionのような位置づけで、uses で GitHub Action を指定して with で指定したパラメーターが、 INPUT_
プレフィックスが付いて、大文字化された値が環境変数としてActionのDockerコンテナーに渡されます。
なので、例えば
cdk_subcommand
→ INPUT_CDK_SUBCOMMAND
となります。
今回は、 working_dir
で指定した相対パスとなるように cdk init
を行っている点がポイントです。
これを、workflow でビルドやデプロイしたいリポジトリーへ push します。
cdk init/CDK を使うコードの作成
ここに関しては、特にこの記事のテーマとしては特記することはありません。
ただ単に、CDK が動く環境で以下のコマンドを実行するだけです。
今回は、 cdk init
で作られる CloudFormation Stack が作られれば良いため、特に Python のコードの追加・変更・削除は行っていません。
cdk init --language python
苦労した点
GitHub Actions という名前の紛らわしさ
Action 定義あっての workflow と勘違いしてしまう。。。
GitHub Workflow なら、やりたい目的を達成するために Action という部品を組み合わせて workflow で処理するんだとわかりやすいと思うのですが、
個々の Action がメインのようなサービス名なのがイマイチ。
Action が使いたいのではなくて、ビルドしたりデプロイしたりするのを自動化したいから、目的を達成するのに名前が非直感的かな?と。
些細なことですが、理解するのに苦労した理由の一つのように思えます。実は workflow やその中のAction で使うコード(ビルド・デプロイ対象) は clone する step が必要
actions/checkout@v1
という Action を指定した step があります。
これは、Action の Docker コンテナーが実行時にマウントする WORKSPACE の場所へ、
その workflow 定義がコミットされているリポジトリーの内容を clone するためのものです。
これが必要であると気づくまでが、最も時間を要しました。
workflow 定義と共に clone されているのですが、そのパスはマウントされないですし、
Action 定義でもマウント出来るようには出来なくて困りました。
まぁ、他のリポジトリーのコードがビルド対象です!と言った場合に、確かにその方が要らぬコードが混入しないので正しいかも。Docker のbest practice に従った対応を入れていると動かないことも
Docker コンテナー内で作業を行うユーザーが root でないと、ファイルアクセスのパーミッションが無くて動きません。 工夫すれば動くのかも知れませんが、流石にそこまでのメリットはなさそう。。。
参考にしたサイト
zshでgit switchが補完されるようにする
前回の記事で、Ubuntuへzshをインストールしたはいいが、git switch
が補完されずに困っていた。
poad1010.hatenablog.com
調べてみると、こんなIssue が! github.com
どうやら、gitリポジトリのmasterにあるgit-completionを使えば良さそう。
mkdir -p ~/.zsh curl -o ~/.zsh/git-completion.bash https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash curl -o ~/.zsh/_git https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.zsh echo "# Load completion files from the ~/.zsh directory." >> ~/.zshrc echo "zstyle ':completion:*:*:git:*' script ~/.zsh/git-completion.bash" >> ~/.zshrc echo "fpath=(~/.zsh $fpath)" >> ~/.zshrc echo "autoload -Uz compinit && compinit" >> ~/.zshrc
これでzshを立ち上げ直したら、見事!git switch
が保管できた!
ちなみに、git switchは、最近、checkout -b
ではなく、switch -c
を使えだとか、checkoutの代わりにswitchを使えという流れみたいなので、gitをアップデートして、switchコマンドに慣れておいた方がいい。
この辺を読めば、Ubuntu bionicでも最新のgitが使える。 text.baldanders.info
zshでzsh-completions
目的
家の macOS Catalina をようやく、bash から zsh へ移行した。 bashよりも使いやすいため、Dockerコンテナーを使って設定を試し、その手順を書き残そうと思う。
手順
docker pull
docker pull ubuntu:bionic
docker run と最新化
docker run --rm -it --name ubuntu ubuntu:bionic bash
apt update -qq apt full-upgrade -qqy
zsh と git のインストール
apt install -qqy --no-install-recommends git ca-certificates apt install -qqy --no-install-recommends zsh
Prezto のインストール
zsh cd $HOME git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"
setopt EXTENDED_GLOB for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}" done
これで Prezto のインストールはOK
zsh-completions
git clone https://github.com/zsh-users/zsh-completions.git "${ZDOTDIR:-$HOME}/.zsh-completions" echo 'fpath=(${ZDOTDIR:-$HOME}/.zsh-completions/src $fpath)' >> $HOME/.zshrc
zsh-completions のインストールもこれで良い。
というか。。。
公式サイトの手順でaptリポジトリーを追加しようにも、証明書の期限切れ?らしくてエラーとなるオプションで回避出来はするはずだけども、セキュリティー的によくないからやってない。 https://software.opensuse.org/download.html?project=shells%3Azsh-users%3Azsh-completions&package=zsh-completions
echo 'deb http://download.opensuse.org/repositories/shells:/zsh-users:/zsh-completions/xUbuntu_18.04/ /' > /etc/apt/sources.list.d/shells:zsh-users:zsh-completions.list wget -nv https://download.opensuse.org/repositories/shells:zsh-users:zsh-completions/xUbuntu_18.04/Release.key -O Release.key apt-key add - < Release.key apt update -qq W: GPG error: http://download.opensuse.org/repositories/shells:/zsh-users:/zsh-completions/xUbuntu_18.04 InRelease: The following signatures were invalid: EXPKEYSIG 9CBE063CAB8FE1F1 shells:zsh-users:zsh-completions OBS Project <shells:zsh-users:zsh-completions@build.opensuse.org> E: The repository 'http://download.opensuse.org/repositories/shells:/zsh-users:/zsh-completions/xUbuntu_18.04 InRelease' is not signed.
bashのcomplationよりも優秀で、↓のように候補が一覧表示されたりする、
$ git c<tab> -- common commands -- checkout -- checkout a branch or paths to the working tree clone -- clone a repository into a new directory commit -- record changes to the repository
追記
テーマ変更の方法もメモしとく
# テーマ一覧 prompt -l # テーマをプレビュー prompt -p <テーマ名> # すべてのテーマをプレビュー prompt -p # テーマを適用(再起動したら戻る) prompt <テーマ名> # テーマ適用(.zpreztorc) zstyle ':prezto:module:prompt' theme '<テーマ名>'
OpenJDK まとめ(2019年5月6日版)
Oracle JDKの公開アップデート提供が終了したことで色々と騒ぎになっていますが、 サードパーティ製のOpenJDK(OpenJDKのディストリビューション)を使えば大抵は解決するだろう。 楽観的ではなくOracleがJava 11をリリースするタイミングで、 JavaFXやJava Mission Control/Java Flight RecorderなどをOSS化しているので、 乗り換えれば良いというお話です。
ちなみに、Java、Java SEが有償化したのではなく、 OpenJDKのディストリビューションのひとつである Oracle JDK の公開アップデートが終了した話のまとめは 「Java 有償化」で誤解する人になるべく分かりやすく説明するためのまとめ - Togetter や、なぜ「Javaが有償化する」と誤解されてしまうのか考えてみる - kazokmr's Blog をご覧下さい。
さて、ここからが本題。
数あるOpenJDKのうち、どれを使えばいいの?ということになりそうなので、 OpenJDKのディストリビューションにはどんなものがあるかご紹介します。
※ 筆者はJavaのいちユーザーに過ぎないため、細かい間違いなどはあるかと思いますがご了承ください。
OpenJDK (Oracle公式バイナリ)
Oracleが中心(あくまでも中心であって、Oracle以外のベンダーも開発に参加しています。新機能の追加は主にOracleらしいです。)に開発されているOpenJDKのOpenJDKプロジェクトによるビルド。 6ヶ月毎にアップデートされて行く。 メジャーバージョンが変わって行くものの、実は今までのOracle JDKでは、 同じメジャーバージョンのアップデートリリースで機能追加が行われていたものが、 きちんと不具合修正のみと機能追加を含むという採番ルールに変わっただけという。。。
JDKの新しいリリース・モデル、および提供ライセンスについて
Red Hat版OpenJDK (この子はだけは無償ではないです)
Red Hat Developer | Red Hat OpenJDK Download
OpenJDKのセキュリティアップデートなどは、JDK 7の頃からRed Hat(最近、RedとHatの間にスペース入るようになったらしい。どうでもいいけど)が中心に行っているそうで、Red Hat Enterprise Linuxと、Windows版が提供されている。
LTSサポートあり。
無償で使えるのはWindows版(おそらくWindows Serverを除く?)だけなので、開発者向けの配布だそうです。
開発者向けの配布で、商用利用はサブスクリプションに加入する必要があるとのこと。
LIBERICA JDK
BellSoft | Java Platform and Applications Experts
BellSoft が提供しているOpenJDKディストリビューション。 LTSサポートあり。 AlpineLinux (must-libc)版あり?(少なくともDockerイメージは提供されています) JavaFX(多分OpenFX)も付属。 Windowsの32bit版もある。
多分、未だJigsaw対応出来ていなくて、Java 8のままなんだけども。。。というプロジェクトや、幾ら何でも6ヶ月毎の更新は対応が間に合わないという型の乗り換え先の最有力候補なんじゃなかろうか?
現状、後述のZuluの方がAlpineLinux対応はしっかりしているらしいです。
では少しだけw
— Takahiro YAMADA (@yamadamn) 2019年5月6日
Liberica JDK(一応Capital)を私が推すのは、あくまでクライアント用でJavaFXを利用していたところです。
先ほどツイートが見えたばかりですが、実はAlpineとかDocker対応はかなり中途半端です。
こちらを参考にしてください (他力本願) https://t.co/3dP7uzaPy0
Zulu Enterprise
Get Java Support OpenJDK Support subscriptions Java Security Updates
Azul Systemsが提供しているOpenJDKディストリビューション。 LTSサポートあり。 AlpineLinux (must-libc)版あり。 ライセンスはOpenJDKと同じGPLv2+クラスパス例外。 Java 11からはLICENSE テキストファイルが同封されなくなったが、同封のreadme.txtに記載されている。 また、それに加えてZulu/Azul Systemsの免責事項などが記載された利用規約が存在する。(記述内容がGPLv2+クラスパス例外と矛盾する場合はGPLv2+クラスパス例外が優先されるようなことが英語で書かれている)
LIBERICA JDKの次に有力な候補ではないかと思われる。(特にAlpineLinuxを使う場合)
ちなみに、ソースコードは要求しないと貰えないようです。 (昔のインターネット回線が遅かったり、常時接続じゃなかった頃を思い出させられる)
Amazon Corretto
Amazon Corretto(本番環境に対応したOpenJDKディストリビューション)| AWS
Amazon(AWS)が提供しているOpenJDKディストリビューション。 LTSサポートあり。 Windows版、Mac版もある。 基本的にはAmazon Linux向けかな? Javaの父であるJames Goslingは、現在Amazonに所属していることもあって話題となった。 Amazon Linux 2ベースで動いているJavaアプリは、これを使うのが良いのだろう。 (うちのプロジェクトは、AWSに乗っていても、後発のAmazon Linuxに乗り換えてすらいないで 他のOpenJDKディストリビューションに乗り換えましたけどね)
SapMachine
SapMachine | An OpenJDK release maintained and supported by SAP
SAPが提供が提供しているOpenJDKディストリビューション。 LTSサポートあり。 PPC用Linux版があるのが特徴。
AdoptOpenJDK
AdoptOpenJDK - Open source, prebuilt OpenJDK binaries
AdoptOpenJDKコミュニティが提供しているOpenJDKディストリビューション。 AdoptOpenJDKプロジェクト自体は、OpenJDKのビルドファームということで、 マイクロソフト含めて様々なベンダーがスポンサーとなっている。 HotSpot VM(Oracle JDKをはじめ、各OpenJDKディストリビューションはこれ)ベースと、 IBMのOpenJ9ベースの両方を提供しているのが特徴。 LTSサポートあり。
ただし、政治的な都合でTCKと呼ばれる互換性確認テストを通せていない。 (AdoptOpenJDKをTCK通したら、他のOpenJDKディストリビューションの存在意義が皆無になるから、 Oracleが嫌がっているという風の噂も。。。噂ですからね)
ちなみに、Windows版にOpenFXをバンドルする予定があるとか。
おまけ
IcedTea
https://icedtea.classpath.org/wiki/Main_Page
Java 8までのRed HatのOpenJDKディストリビューション。 (ページタイトルがMainPageって。。。)
IcedTea-Web
上記IceTeaから分離したJava Web StartのOSS実装。 今後、Java Web Startを無償で使うなら、IceTea-Webになるのだろう。
謝辞
OpenJDKソムリエの @yamadamn さん、ご確認およびご指摘いただきましてありがとうございました。
Vagrant で Tiny Core Linux!
boot2docker を使ってみたところ、その起動の速さに驚かされた。 そこで、Vagrant でTiny Core Linuxを使ったら起動が早くてカスタマイズしやすいヘッドレスなLinux環境が構築できるのでは?と思ったのでやってみた。
Tiny Core Linuxのインストール 公式サイトからCorePlusのISOイメージをダウンロードしてインストール。
Vagrant Box化するために色々と設定(ここがハマりどころポイントその1) 2.1. vagrant ユーザーの追加 2.2. (ここ重要!) /etc/sudoers に vagrant ユーザーを追加 visudoなんて使えないので、vimなりechoなり。。。 2.3. curl と opensshをインストール tceやtc-load使います。 2.4. (ここ重要!)
/opt/bootlocal.sh
に 以下を追加
/usr/local/etc/init.d/openssh start
2.5. (ここも重要!) sshd_config を作成 とりあえずコピーで大丈夫です。
cp /usr/local/etc/ssh/sshd_config.orig /usr/local/etc/ssh/sshd_config
2.6. (ここ超重要!!!) /opt/.filetool.lst に変更したファイルパスを追加する こんな感じになります。
opt home etc/shadow etc/passwd etc/sudoers usr/local/etc/ssh/sshd_config
2.7. (ここも超重要!!!) filetool.sh -b
してバックアップに含める
Tiny Core Linux は、起動毎にルートファイルシステムをバックアップから復元している(?)ようで、これをしないで再起動すると、変更が吹き飛びます。
2.8. VM再起動
2.9. (やや重要) ホストのSSH鍵を /opt/.filetool.lst
に追加してfiletool.sh -b
2.10. (基本) Vagrantの公開鍵を /home/vagrant/.ssh配下に配置する
- Box 化
- (やや重要) Vagrantfileの編集(なければ作って) こんなんになります。
module VagrantPlugins module GuestTinyCoreLinux module Cap class Halt def self.halt(machine) begin machine.communicate.sudo('poweroff') rescue Net::SSH::Disconnect, IOError # Ignore, this probably means connection closed because it # shut down and SSHd was stopped. end end end end class Guest < Vagrant.plugin('2', :guest) def detect?(machine) machine.communicate.test('[ "$(cat /etc/os-release | grep ^NAME | cut -d = -f2)" = "TinyCore" ]') end end end end Vagrant.configure("2") do |config| config.vm.define "tinycore" do |config| config.vm.box = "poad/tinycorelinux" config.ssh.username = "vagrant" config.ssh.password = "vagrant" config.ssh.shell = "sh" config.vm.synced_folder ".", "/vagrant", disabled: true config.vm.boot_timeout = 75 config.vm.graceful_halt_timeout = 35 config.vm.provider "virtualbox" do |vb| vb.memory = "2048" end end end
解説
module VagrantPlugins module GuestTinyCoreLinux module Cap class Halt def self.halt(machine) begin machine.communicate.sudo('poweroff') rescue Net::SSH::Disconnect, IOError # Ignore, this probably means connection closed because it # shut down and SSHd was stopped. end end end end class Guest < Vagrant.plugin('2', :guest) def detect?(machine) machine.communicate.test('[ "$(cat /etc/os-release | grep ^NAME | cut -d = -f2)" = "TinyCore" ]') end end end end
は、Vagrant Plugin の記述になります。
Tiny Core Linux か否かを Guest classの detect?メソッドを使用して確認します。(/etc/os-releaseのNAMEが TinyCoreであれば有効となるプラグインとなります。)
Tiny Core Linux であれば、vagrant halt
コマンドの実体は poweroff
を使うようにしています。
これで、Tiny Core Linux の起動と終了には問題が無くなった。 VirtualBoxの共有フォルダーが使えない?は仕方ない。
OpenBSDをVirtualBoxだけでUEFIインストール
VirtualBoxを使用して、UEFI起動するOpenBSD 6.4のVMを作成する手順です。 UEFI起動するようにOpenBSD 6.4をインストールするには、 公式の手順ではUSB FlashメモリーなどのUSB接続のストレージが必要となってしまいます。 でも、VM作るのにUSB接続のストレージなんか使いたくない!って人のための手順です。
- Linux VM(〜BSDのVMでも良いし、VirtualBoxでマウント出来るディスクイメージへdd出来るなら、ホストOSを使っても良い)を用意します。
- Linux VMに1GBくらいの仮想HDDを追加します。
- https://www.openbsd.org/faq/faq4.html#Download から、installXX.fs をダウンロードします。
- Linux VMから 2.で追加した仮想HDDへ、ddコマンドを使用してinstallXX.fs イメージを書き込みます。(ここ重要)
- OpenBSDをインストールするVMを作成し、installXX.fs イメージを書き込んだ仮想HDDを接続します。
- このこのVMには、OpenBSDをインストールする先の仮想HDDも必要となります
本当なら、installXX.iso や cdXX.isoでUEFI起動出来ればいいのですけどね。。。
余談ですが、上記手順でインストールして、拙著のQiita記事qiita.com の手順に構築したVagrant Boxもあります。 app.vagrantup.com
Phoenix (Elixir) を動かしてみる
準備
Elixir のインストール
基本的にはPhoenixやElixirの公式サイトを参照していただきたい。 Homebrewインストール済みのmacOS を使って開発しているため、Homebrewを使ってインストールする。
brew install elixir
インストールされたバージョン
$ iex -v Erlang/OTP 21 [erts-10.2.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace] IEx 1.7.4 (compiled with Erlang/OTP 21) $
PostgreSQLの起動
ホストに直接インストールしても良い。 インストール手順はPostgreSQLの公式サイトを参照していただきたい。
今回は、ホストの環境はあまり汚したくないため、Dockerコンテナーとして起動する。
docker run -d --name postgres -p 5432:5432 postgres:alpine
実行
Phoenix をインストールして起動する。
mix local.hex # Phoenix のインストール mix archive.install hex phx_new 1.4.0 # プロジェクト作成 mix phx.new phoenix_example cd phoenix_example # DBの設定(create databaseされます) mix ecto.create # Phoenix サーバーの起動 mix phx.server
http://localhost:4000 へアクセスすれば、Phoenixのデフォルトページが表示されるはず。
備考
Phoenix のインストール( mix archive.install hex phx_new
)時にバージョン指定しないと 1.2.5がインストールされる。
mix phx.server
に失敗するため、バージョン指定している。