AWS ECRを使ってみる

毎回DockerfileをGithubから取ってきてbuildしてrunするのはやっぱりイケけてないのでAWSのコンテナレジストリことECRを使ってみます。

マネジメントコンソールからECRのページに行き、[リポジトリの作成]を押します。

リポジトリ名は***.amazonaws.com/<名前空間>/<リポジトリ名>みたいな感じでつけれます。名前空間はなくても大丈夫なようです。

リポジトリを作成できたら、イメージをpushするためにアカウント認証を行いましょう。awsコマンドはbrew install awscliなどでインストールします。認証をしていない場合はaws configureをしてください。

以下のコマンドでdocker loginできます

$(aws ecr get-login --no-include-email --region ap-northeast-1)

外側をかこっている$()をつけないとただdocker loginのコマンドが表示されるだけなので必ずつけて実行しましょう。リージョンはECRのリポジトリを作ったとこにします。

適当なDockerfileを用意し、ECRのリポジトリにタグをつけてdocker buildを行います。

cd <path-to-dockerfile>/
docker build -t ***.amazonaws.com/garicchi/test-1 ./

docker pushを行います。

docker push ***.amazonaws.com/garicchi/test-1

無事pushできました。


せっかくなのでpullしてみます。

docker pull ****.amazonaws.com/garicchi/test-1

無事pullできました。

docker build時やpush時に長いリポジトリ名を書かなきゃなのは辛いですが普通に簡単に使うことができました。

docker-composeではどうやってpullするのか気になったので調べてみると、aws ecr docker-loginをちゃんとしておくとあとはdocker-composeのimage:タグにレジストリのURLつきでイメージ名を書くと、pullしてくれるようです。

AWS ECR と docker-compose – Qiita https://qiita.com/iwai/items/ec4103890b983039163b

git log ancestry-pathについて

git logの–ancestry-pathオプションがよくわからなかったので調べて見た。

まずこんな感じのコミットログを考える

*   e3b7b68 2019-02-03 togai-r  (HEAD -> master) I
|\
| * 659e5da 2019-02-03 togai-r (br-1) H
| * bcb7e69 2019-02-03 togai-r G
| |\
| | * a8b93fa 2019-02-03 togai-r (br-2) D
| * | 9103739 2019-02-03 togai-r E
| |/
| * 71c4055 2019-02-03 togai-r B
* | 2a3c429 2019-02-03 togai-r F
|/
* 7963add 2019-02-03 togai-r A

ここでgit log –graph –oneline 9103739..e3b7b68を実行すると、以下が出力される。

*   e3b7b68 (HEAD -> master) I
|\
| * 659e5da (br-1) H
| * bcb7e69 G
| * a8b93fa (br-2) D
* 2a3c429 F

git logに<rev1>..<rev2>とrevisionを2つのドットで繋いで範囲にすると、「<rev2>の祖先のログから<rev1>の祖先を減算したログ」を出力する。

ここでgit log –graph –oneline –ancestry-path 9103739..e3b7b68を実行してみよう。

* e3b7b68 (HEAD -> master) I
* 659e5da (br-1) H
* bcb7e69 G

a8b93faと2a3c429コミットがログから消えた。–ancestry-pathをつけていない状態ではa8b93faと2a3c429があったのに、つけるとa8b93faと2a3c429が消えた。この2つのリビジョンの法則性としては2つのドットの前に指定した9103739の子孫ではないということだ。

–ancestry-pathの働きは、「2つのドットの後ろにつけたリビジョンの子孫でないものを削除する」というものになる。

つまり、git log –ancestry-path <rev1>..<rev2>は、「<rev2>の祖先から<rev1>の祖先を削除し、さらに<rev1>の子孫でないものを削除する」意味になる。

これは結果的になにをしているかというと、「<rev1>から<rev2>の間にあるコミットだけ抽出」という結果になる。

2つのリビジョン間にあるコミットだけを抽出したい時、git log –ancestry-path <rev1>..<rev2>は便利に使うことができる。

参考文献

https://stackoverflow.com/questions/36433572/how-does-ancestry-path-work-with-git-log

Macをサーバーにしてjenkins jnlpデーモンを起動させたとき、謎にterminatedになる現象

現象

Macをビルドサーバーとして、Jenkinsのjnlp slaveを起動していたのですが10数分〜1時間ぐらいで接続が切れる。

jnlp slaveはnohupとlaunchdでの起動試したがどちらも接続が切れる

jnlp slaveをフォアグラウンドで起動していると接続は切れない

masterのログをみても以下のようにしかでない

コネクションが切断されました。

<br>
java.nio.channels.ClosedChannelException<br>
	at org.jenkinsci.remoting.protocol.NetworkLayer.onRecvClosed(NetworkLayer.java:154)<br>
	at org.jenkinsci.remoting.protocol.impl.NIONetworkLayer.ready(NIONetworkLayer.java:142)<br>
	at org.jenkinsci.remoting.protocol.IOHub$OnReady.run(IOHub.java:795)<br>
	at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)<br>
	at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)<br>
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)<br>
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)<br>
	at java.lang.Thread.run(Thread.java:748)<br>

slave側のログをみても、「terminated」としか書いてない。

psコマンドでプロセスを見るとプロセスは生きている

原因

ssh接続を切っている間に、Macが自動スリープしていた

Macで画面共有を有効化しているとき、ssh接続をするとスリープモードから自動復旧するらしく、利用者側からはスリープしてるようにみえなかった

Macがスリープするので、プロセスも一時停止する→jnlp接続が切れる

対策

Preferences->省電力->ディスプレイがオフの時にコンピューターをスリープしない

にチェックをいれるだけ

感想

1週間ぐらい悩みました。つらい

Dockerコンテナ内でssh keyを使う

Dockerコンテナでビルドパイプラインなどを作っていると、コンテナ内からgit fetchしたくなります。しかしsshでgit fetchしようとすると、コンテナ内との鍵の管理がめんどうになります。

コンテナ内でssh用の鍵を使う方法としては

  1. コンテナ用の鍵を生成してbuild時にコピーする
  2. ホストの.sshをコンテナにマウントする

の2パターンが考えられます。

1の場合、ホストだけでなくコンテナ用の鍵をいちいち生成しなくてはならず、またGithubなどのdeploykeyに登録をしないといけなくなります。さらにDockerfileがgit管理されている環境ではコンテナ用のprivate keyをリポジトリにコミットしてしまう恐れもあります。

したがって2の場合を考えて行きたいのですが、普通に.sshをコンテナにマウントすると、.ssh/configのownerがホスト側のユーザーになってしまい、コンテナからsshしようとするとpermission errorになってしまいます。

解決策としては、マウント先は一時ファイルに.sshをマウントしておき、コンテナ実行時にコンテナのホームディレクトリにコピーすることで.sshのpermissionが正しくなります。

コンテナ実行時に.sshをコピーするために、ENTRYPOINTは以下のようなシェルスクリプトにします。

あとはdocker run時に.sshを一時ファイルへマウントすればOKです

docker run -v /home/user/.ssh:/tmp/.ssh

[go][python] 依存パッケージのファイルは先にCOPYしてdocker buildを高速化する

docker buildすると依存パッケージのインストールが走ります。

理想的には依存パッケージに変更がなければ依存パッケージのインストールはキャッシュしたいところです。

しかしながらうまくDockerfileを作らないと毎回docker build時に依存パッケージのインストールが走ってしまいます。

依存パッケージのインストールをキャッシュするためには依存パッケージを記述したファイルのみ、先にCOPYしてパッケージのインストールを行います。
ソースコードはDockerfileの最後の方でCOPYします。
こうすることでソースコードに変更が合った場合、依存パッケージのインストールはキャッシュされ、ソースコードのコピーのみ処理が走ります。

goの場合、depパッケージマネージャを使うならGoPkg.tomlとGoPkg.lockのみ先にコピーします。
パッケージインストール時はdep ensure -vendor-only=trueにすることでソースコードの解析が走らずにパッケージのインストールが走ります。dep ensureのみで実行してしまうと、この部分がソースコードに依存してしまうのでソースコードに変更があるとパッケージの再インストールが走ってしまいます。

サンプル

https://github.com/garicchi/docker-sample