Software development of explosion! -夢の破片(カケラ)たちの日々-

ソフトウェア開発を中心としたコンピューター関連のネタを扱ったブログです

Software development is passion and explosion!

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 CLIAWS 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:3npmpython3pipawsclicdk をインストールします。 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_subcommandINPUT_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 でないと、ファイルアクセスのパーミッションが無くて動きません。 工夫すれば動くのかも知れませんが、流石にそこまでのメリットはなさそう。。。

参考にしたサイト

qiita.com

zshでgit switchが補完されるようにする

前回の記事で、Ubuntuzshをインストールしたはいいが、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 git://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 '<テーマ名>'

個人的には、元のbashみたいに見える redhat テーマが好き

OpenJDK まとめ(2019年5月6日版)

Oracle JDKの公開アップデート提供が終了したことで色々と騒ぎになっていますが、 サードパーティ製のOpenJDK(OpenJDKのディストリビューション)を使えば大抵は解決するだろう。 楽観的ではなくOracleJava 11をリリースするタイミングで、 JavaFXJava Mission Control/Java Flight RecorderなどをOSS化しているので、 乗り換えれば良いというお話です。

ちなみに、JavaJava SEが有償化したのではなく、 OpenJDKのディストリビューションのひとつである Oracle JDK の公開アップデートが終了した話のまとめは 「Java 有償化」で誤解する人になるべく分かりやすく説明するためのまとめ - Togetter や、なぜ「Javaが有償化する」と誤解されてしまうのか考えてみる - kazokmr's Blog をご覧下さい。

さて、ここからが本題。

数あるOpenJDKのうち、どれを使えばいいの?ということになりそうなので、 OpenJDKのディストリビューションにはどんなものがあるかご紹介します。

※ 筆者はJavaのいちユーザーに過ぎないため、細かい間違いなどはあるかと思いますがご了承ください。

OpenJDK (Oracle公式バイナリ)

OpenJDK

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対応はしっかりしているらしいです。

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サポートあり。 PPCLinux版があるのが特徴。

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

IcedTea-Web - IcedTea

上記IceTeaから分離したJava Web StartOSS実装。 今後、Java Web Startを無償で使うなら、IceTea-Webになるのだろう。

謝辞

OpenJDKソムリエの @yamadamn さん、ご確認およびご指摘いただきましてありがとうございました。

Vagrant で Tiny Core Linux!

boot2docker を使ってみたところ、その起動の速さに驚かされた。 そこで、Vagrant でTiny Core Linuxを使ったら起動が早くてカスタマイズしやすいヘッドレスなLinux環境が構築できるのでは?と思ったのでやってみた。

  1. Tiny Core Linuxのインストール 公式サイトからCorePlusのISOイメージをダウンロードしてインストール。

  2. 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配下に配置する

  1. Box 化
  2. (やや重要) 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接続のストレージなんか使いたくない!って人のための手順です。

  1. Linux VM(〜BSDVMでも良いし、VirtualBoxでマウント出来るディスクイメージへdd出来るなら、ホストOSを使っても良い)を用意します。
  2. Linux VMに1GBくらいの仮想HDDを追加します。
  3. https://www.openbsd.org/faq/faq4.html#Download から、installXX.fs をダウンロードします。
  4. Linux VMから 2.で追加した仮想HDDへ、ddコマンドを使用してinstallXX.fs イメージを書き込みます。(ここ重要)
  5. OpenBSDをインストールするVMを作成し、installXX.fs イメージを書き込んだ仮想HDDを接続します。
  6. このこのVMには、OpenBSDをインストールする先の仮想HDDも必要となります
    1. VMUEFIオプションを有効にして起動すると、OpenBSDインストーラーが起動するため、画面に従ってインストールを行います。

本当なら、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 に失敗するため、バージョン指定している。

d.hatena.ne.jp