- 投稿日:2019-02-11T22:47:27+09:00
AWS Lambda で C のバイナリを動かす
ありふれたネタですが、 Lambda のカスタムランタイムで C を動かしてみました。
ディレクトリ構成
. ├── bin │ ├── bootstrap │ └── lambda_function ├── docker-compose.yml ├── Dockerfile └── src ├── lambda_function.c └── Makefile一連のコードは https://github.com/tsubasaogawa/lambda-with-c にあげています。
手順
概要
- C のソースを書く
- Lambda と同じ実行環境でソースをコンパイルする
- bootstrap を修正する
- Lambda にアップロードする
詳細
C のソースを書く
普段どおりソースを書きます。今回は「標準入力された内容を出力する」だけの簡単なものを作ってみました。
lambda_function.c#include <stdio.h> int main(void) { char buf[512]; while(1) { /* Obtain from Stdin https://qiita.com/mpyw/items/aff12a6ff2c7726ed1d8 */ if(scanf("%511[^\n]%*[^\n]", buf) != 1) { break; } /* Ignore linefeed */ scanf("%*c"); printf("%s\n", buf); } return 0; }MakefilePROGRAM = lambda_function CC = gcc CFLAGS = -Wall OBJS = $(PROGRAM).o $(PROGRAM): $(OBJS) $(CC) $(CFLAGS) -o $(PROGRAM) $(OBJS) $(OBJS): $(PROGRAM).c $(CC) -c $(PROGRAM).c .PHONY: clean clean: rm -f $(PROGRAM) $(OBJS) .PHONY: clean_obj clean_obj: rm -f $(OBJS)Lambda と同じ実行環境でソースをコンパイルする
Lambda で動かすので、Lambda と同じ環境でコンパイルする必要があります。
Lambda 実行環境と利用できるライブラリ によると Amazon Linux を使っている (2019/02 時点) ことがわかるため、Amazon Linux のコンテナ上でコンパイルすることにします。DockerfileFROM amazonlinux:2 MAINTAINER tsubasaogawa WORKDIR /usr/local/src/lambda-with-c RUN set -x && yum install -y gcc make # ADD ./bootstrap . COPY ./src/lambda_function.c . COPY ./src/Makefile . RUN make && make clean_objなんとなく Amazon Linux 2 にしてしまいました。docker-compose は以下です。
docker-compose.ymlversion: '3' services: lambda-with-c-compiler: build: . volumes: - ./bin:/var/tmp command: /bin/bash -c 'cp -r /usr/local/src/lambda-with-c/lambda_function /var/tmp'コンテナビルド時に
make
で作られたバイナリを、マウントしたディレクトリにコピーしています。また、コンテナを実行するとホストのbin/
配下にバイナリが作られます。$ docker-compose build $ docker-compose up -d $ ls -l bin/lambda_function -rwxr-xr-x 1 root root 8232 Feb 11 12:49 bin/lambda_functionbootstrap を修正する
カスタムランタイムを使用すると、
bootstrap
というファイルが実行されます。bootstrap 経由でバイナリを実行するような形になります。
チュートリアル では、シェルスクリプトで bootstrap が書かれています。これを一部 (というかほとんど) 流用します。bootstrap#!/bin/sh set -euo pipefail # Processing while true do HEADERS="$(mktemp)" # Get an event EVENT_DATA=$(curl -sS -LD "$HEADERS" -X GET "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next") REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2) # Execute the handler function from the script EXEC="$LAMBDA_TASK_ROOT/$(echo "$_HANDLER" | cut -d. -f1)" RESPONSE=$(echo "$EVENT_DATA" | $EXEC) # Send the response curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d "$RESPONSE" doneLambda にアップロードする
成果物を zip にして Lambda へアップロードします。Role は予め適当なものを用意してください。
Lambdaへアップロード$ cd bin $ zip ../lambda_function.zip ./* $ cd .. $ ls -l lambda_function.zip -rw-rw-r-- 1 vagrant vagrant 3032 Feb 11 12:55 lambda_function.zip $ aws lambda create-function --function-name lambda-with-c \ --zip-file fileb://lambda_function.zip --handler lambda_function.handler \ --runtime provided --role arn:aws:iam::***:role/role_name試しに実行してみます。
実行$ aws lambda invoke --function-name lambda-with-c \ --invocation-type RequestResponse \ --payload '{ "test1": "value1" }' \ /tmp/lambda-with-c.log { "StatusCode": 200, "ExecutedVersion": "$LATEST" }実行結果$ cat /tmp/lambda-with-c.log { "test1": "value1" }よさそうです。引数が得られたので、あとは自由にパースして使えそうです。
おわりに
- Lambda のカスタムランタイムを使って、 C で作られたバイナリを動かしてみた
- Amazon Linux 上でコンパイルを行うと安心
- カスタムランタイム使用時は bootstrap というファイルがまず実行される
- bootstrap 経由でバイナリを実行する
- なお、C++ では便利なライブラリが公開されているのでこれを使うと幸せになれそう
- 参考記事
- 投稿日:2019-02-11T19:41:08+09:00
Dockerのマルチステージビルド機能でコンテナ上のMavenビルド
Dockerのマルチステージビルドについて。
これまでコンテナ環境で動かすアプリケーション自体のビルド(warファイル作成)はホストOSとかのコンテナ外で行っていた。
というのも、やろうと思えばカスタムイメージのビルド内でアプリケーションのビルド(Dockerfileでwarをコピーする代わりに、内部でビルドする)も当然可能だが、アプリケーションの実行環境(ランタイム環境)にビルドだけに必要な(Mavenなどの)パッケージを入れるのはあまり良い構成ではない。そこで、「アプリケーションのビルド(warファイル作成)だけを行うイメージ」と「作成されたwarファイルをtomcatイメージに取り込んだイメージ(既存処理)」の二つを順番に行うマルチステージビルドというDockerの機能を使うことで、ビルド環境とランタイム環境を分離しつつ、ぜんぶコンテナ内で完結する構成とすることができる。
todo: 登場人物の図を描こう…
参考
これまで
アプリケーションをMaven Buildするイメージ作成の準備
まずはDockerfileを作るための手順を確認する。
今までUbuntuでやっていたのでここでもUbuntuで(なぜかDebianだとうまくいかなかった)
コンテナ起動
root@chaource:~# docker run -it ubuntu bash root@d8b1e0c1361f:/# root@d8b1e0c1361f:/# ls bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var root@d8b1e0c1361f:/#
Maven
とGit
のインストールroot@d8b1e0c1361f:/# cat /etc/apt/sources.list # See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to # newer versions of the distribution. deb http://archive.ubuntu.com/ubuntu/ bionic main restricted # deb-src http://archive.ubuntu.com/ubuntu/ bionic main restricted ## Major bug fix updates produced after the final release of the ## distribution. deb http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted # deb-src http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted ## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu ## team. Also, please note that software in universe WILL NOT receive any ## review or updates from the Ubuntu security team. deb http://archive.ubuntu.com/ubuntu/ bionic universe # deb-src http://archive.ubuntu.com/ubuntu/ bionic universe deb http://archive.ubuntu.com/ubuntu/ bionic-updates universe # deb-src http://archive.ubuntu.com/ubuntu/ bionic-updates universe ## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu ## team, and may not be under a free licence. Please satisfy yourself as to ## your rights to use the software. Also, please note that software in ## multiverse WILL NOT receive any review or updates from the Ubuntu ## security team. deb http://archive.ubuntu.com/ubuntu/ bionic multiverse # deb-src http://archive.ubuntu.com/ubuntu/ bionic multiverse deb http://archive.ubuntu.com/ubuntu/ bionic-updates multiverse # deb-src http://archive.ubuntu.com/ubuntu/ bionic-updates multiverse ## N.B. software from this repository may not have been tested as ## extensively as that contained in the main release, although it includes ## newer versions of some applications which may provide useful features. ## Also, please note that software in backports WILL NOT receive any review ## or updates from the Ubuntu security team. deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted universe multiverse # deb-src http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted universe multiverse ## Uncomment the following two lines to add software from Canonical's ## 'partner' repository. ## This software is not part of Ubuntu, but is offered by Canonical and the ## respective vendors as a service to Ubuntu users. # deb http://archive.canonical.com/ubuntu bionic partner # deb-src http://archive.canonical.com/ubuntu bionic partner deb http://security.ubuntu.com/ubuntu/ bionic-security main restricted # deb-src http://security.ubuntu.com/ubuntu/ bionic-security main restricted deb http://security.ubuntu.com/ubuntu/ bionic-security universe # deb-src http://security.ubuntu.com/ubuntu/ bionic-security universe deb http://security.ubuntu.com/ubuntu/ bionic-security multiverse # deb-src http://security.ubuntu.com/ubuntu/ bionic-security multiverse root@d8b1e0c1361f:/#universeは入ってるけど有効になってない模様
root@d8b1e0c1361f:/# grep universe /etc/apt/sources.list ## team. Also, please note that software in universe WILL NOT receive any deb http://archive.ubuntu.com/ubuntu/ bionic universe # deb-src http://archive.ubuntu.com/ubuntu/ bionic universe deb http://archive.ubuntu.com/ubuntu/ bionic-updates universe # deb-src http://archive.ubuntu.com/ubuntu/ bionic-updates universe deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted universe multiverse # deb-src http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted universe multiverse deb http://security.ubuntu.com/ubuntu/ bionic-security universe # deb-src http://security.ubuntu.com/ubuntu/ bionic-security universe root@d8b1e0c1361f:/# apt install git maven Reading package lists... Done Building dependency tree Reading state information... Done E: Unable to locate package git E: Unable to locate package maven root@d8b1e0c1361f:/#root@d8b1e0c1361f:/# apt update Get:1 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB] Get:2 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB] Get:3 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [339 kB] Get:4 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB] Get:5 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB] Get:6 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages [11.3 MB] : : Fetched 15.5 MB in 1min 2s (248 kB/s) Reading package lists... Done Building dependency tree Reading state information... Done 9 packages can be upgraded. Run 'apt list --upgradable' to see them. root@d8b1e0c1361f:/#root@d8b1e0c1361f:/# apt install git maven Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: : :root@d8b1e0c1361f:/# which git /usr/bin/git root@d8b1e0c1361f:/# which mvn /usr/bin/mvn root@d8b1e0c1361f:/#git cloneする
root@d8b1e0c1361f:/# cd root@d8b1e0c1361f:~# ls root@d8b1e0c1361f:~# mkdir src root@d8b1e0c1361f:~# cd src/ root@d8b1e0c1361f:~/src# git clone https://github.com/zaki-lknr/javaee-memoapp2.git -b v1.0.0 Cloning into 'javaee-memoapp2'... remote: Enumerating objects: 384, done. remote: Counting objects: 100% (384/384), done. remote: Compressing objects: 100% (158/158), done. remote: Total 384 (delta 144), reused 355 (delta 115), pack-reused 0 Receiving objects: 100% (384/384), 39.46 KiB | 1.64 MiB/s, done. Resolving deltas: 100% (144/144), done. Note: checking out '3656f7114c526027c96c0a585b6a5152ce43947c'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name> root@d8b1e0c1361f:~/src#Mavenビルド
root@d8b1e0c1361f:~/src# cd javaee-memoapp2/ root@d8b1e0c1361f:~/src/javaee-memoapp2# root@d8b1e0c1361f:~/src/javaee-memoapp2# root@d8b1e0c1361f:~/src/javaee-memoapp2# root@d8b1e0c1361f:~/src/javaee-memoapp2# mvn package WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1 WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building memoapp2 Maven Webapp 0.0.1-SNAPSHOT [INFO] ------------------------------------------------------------------------ Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-resources-plugin/2.6/maven-resources-plugin-2.6.pom : : Downloaded from central: https://repo.maven.apache.org/maven2/xpp3/xpp3_min/1.1.4c/xpp3_min-1.1.4c.jar (25 kB at 46 kB/s) Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-filtering/1.0-beta-2/maven-filtering-1.0-beta-2.jar (33 kB at 46 kB/s) Downloaded from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0/plexus-utils-3.0.jar (226 kB at 309 kB/s) [INFO] Packaging webapp [INFO] Assembling webapp [memoapp2] in [/root/src/javaee-memoapp2/target/memoapp2] [INFO] Processing war project [INFO] Copying webapp resources [/root/src/javaee-memoapp2/src/main/webapp] [INFO] Webapp assembled in [127 msecs] [INFO] Building war: /root/src/javaee-memoapp2/target/memoapp2.war [INFO] WEB-INF/web.xml already added, skipping [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 01:07 min [INFO] Finished at: 2019-02-11T01:45:09Z [INFO] Final Memory: 19M/46M [INFO] ------------------------------------------------------------------------ root@d8b1e0c1361f:~/src/javaee-memoapp2# root@d8b1e0c1361f:~/src/javaee-memoapp2# root@d8b1e0c1361f:~/src/javaee-memoapp2# ll target/memoapp2.war -rw-r--r-- 1 root root 3905409 Feb 11 01:45 target/memoapp2.war root@d8b1e0c1361f:~/src/javaee-memoapp2# ll /root/src/javaee-memoapp2/target/memoapp2.war -rw-r--r-- 1 root root 3905409 Feb 11 01:45 /root/src/javaee-memoapp2/target/memoapp2.war root@d8b1e0c1361f:~/src/javaee-memoapp2#無事に完了。
まとめ
必要な手順は以下の通り
- apt update
- apt install git maven
- git clone
- mvn package
Dockerfileの作成
ubuntuベースの場合
というわけでマルチステージビルド本番。
やることは、前段で確認した「アプリケーションのビルドそのもの(warファイル作成)の実行」と「作成されたwarファイルをtomcatイメージに取り込み(既存の処理)」の2点※ before
DockerfileFROM ubuntu AS memoapp-build RUN apt update && apt install -y git maven WORKDIR /usr/local/src RUN git clone https://github.com/zaki-lknr/javaee-memoapp2.git \ && cd javaee-memoapp2 \ && mvn package FROM tomcat:8.5 COPY --from=memoapp-build /usr/local/src/javaee-memoapp2/target/memoapp2.war /usr/local/tomcat/webapps/一つ目の
FROM ubuntu AS memoapp-build
は、memoapp-build
という名前でアプリケーションをビルドしwarファイルを作成する処理までを行うイメージを作成する。
二つ目のFROM tomcat:8.5
で、memoapp-build
で作成したwarファイルを(COPY
の--from
オプションで指定して)取り出し、サービス実行用のイメージに取り込んでいる。root@chaource:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE debian latest d508d16c64cd 4 days ago 101MB memoapp latest 2cd39d9db4c2 5 days ago 466MB tomcat 8.5 7ee26c09afb3 2 weeks ago 462MB mysql 5.7 141eda20897f 2 weeks ago 372MB ubuntu latest 20bb25d32758 2 weeks ago 87.5MBmemoapp:latestがすでにあるので
root@chaource:~# docker build -t memoapp-msb . Sending build context to Docker daemon 33.24MB Step 1/5 : FROM ubuntu AS mvn-build ---> 20bb25d32758 Step 2/5 : RUN apt update && apt install -y git maven ---> Running in ec5267d45093 WARNING: apt does not have a stable CLI interface. Use with caution in scripts. Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB] Get:2 http://security.ubuntu.com/ubuntu bionic-security/multiverse amd64 Packages [3451 B] Get:3 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB] Get:4 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [147 kB] Get:5 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [339 kB] Get:6 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB] Get:7 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB] Get:8 http://archive.ubuntu.com/ubuntu bionic/main amd64 Packages [1344 kB] Get:9 http://archive.ubuntu.com/ubuntu bionic/restricted amd64 Packages [13.5 kB] Get:10 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages [11.3 MB] : : [INFO] Packaging webapp [INFO] Assembling webapp [memoapp2] in [/usr/local/src/javaee-memoapp2/target/memoapp2] [INFO] Processing war project [INFO] Copying webapp resources [/usr/local/src/javaee-memoapp2/src/main/webapp] [INFO] Webapp assembled in [151 msecs] [INFO] Building war: /usr/local/src/javaee-memoapp2/target/memoapp2.war [INFO] WEB-INF/web.xml already added, skipping [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 01:14 min [INFO] Finished at: 2019-02-11T08:30:19Z [INFO] Final Memory: 19M/46M [INFO] ------------------------------------------------------------------------ Removing intermediate container 2e53cba3f4b3 ---> 853035d3ed5d Step 5/6 : FROM tomcat:8.5 ---> 7ee26c09afb3 Step 6/6 : COPY --from=memoapp-build /usr/local/src/javaee-memoapp2/target/memoapp2.war /usr/local/tomcat/webapps/ ---> 4fd6539d4164 Successfully built 4fd6539d4164 Successfully tagged memoapp-msb:latestできました。
ただ結構時間かかる。
mavenベースの場合
ubuntuコンテナ内でgit & mavenを
apt update && apt install
するのに結構な時間かかっているので、MavenのOfficialイメージを使ってみよう。
これならmavenは当然最初から入っているし、git
も内蔵しているので、apt
を使う必要がなく、大幅に(私の環境では5,6分)時間短縮できる。できたDockerfileがこちら
DockerfileFROM maven:3.6 AS memoapp-build WORKDIR /usr/local/src RUN git clone https://github.com/zaki-lknr/javaee-memoapp2.git \ && cd javaee-memoapp2 \ && mvn package FROM tomcat:8.5 COPY --from=memoapp-build /usr/local/src/javaee-memoapp2/target/memoapp2.war /usr/local/tomcat/webapps/Docker Composeと連携
連携といっても、参照するDockerfileをマルチステージビルドしている内容にするだけ。
- あらかじめwarファイルを作成
- ↑のwarファイルを使用するカスタムイメージをビルド
- ↑のカスタムイメージとMySQLイメージをコンテナ実行
という手順になっていたが、本記事のマルチステージビルドのDockerfileを使うことで
- warファイルを作成するコンテナ実行
- ↑のwarファイルを使用するカスタムイメージをビルド
- ↑のカスタムイメージとMySQLイメージをコンテナ実行
という手順になり、ホストOS上にビルド環境を用意しなくても実行環境を用意できるようになった。
Mavenみたいな便利なビルドツールがあると、コンテナ化のメリットもあまり感じられないかもしれないけど、ビルドするのに依存する複数のライブラリを手動で入れる必要があったり、特定のプラットフォームでのビルドだと動作に不安があったり、人によってコンパイラのバージョンが異なっていたり、そもそもJavaみたいなクロスプラットフォームなでなく、「ソースを書くのはWindowsだけどビルドはLinux」みたいな場合でも、常に同一の環境でビルドできる、というメリットがある。
ここまでやっておいてなんだけど、OpenShiftで使えるS2Iってこのあたりの機能を含んでいる感じだなー
- 投稿日:2019-02-11T19:19:48+09:00
letsencrypt-nginx-proxy-companionを使って複数ドメイン名に無料SSL証明書を適用する
初めに
Docker Compose等で
* nginx-proxy
* letsencrypt-nginx-proxy-companion
を利用すると自作サービスのコンテナにLet’s EncryptのSSL証明書を適用して公開する事が可能。1単一のコンテナへ以下の様な複数ドメイン名に対してSSL証明書を適用する方法を調査した。
example.com www.example.com結論
利用ドメイン名を指定する環境変数をカンマ区切りで記述すると適用してくれる。2
- 自作サービス側のdocker-compose.yml例
version: '3.3' services: myapp: image: my-app environment: VIRTUAL_HOST: example.com,www.example.com # ← カンマ区切り指定 LETSENCRYPT_HOST: example.com,www.example.com # ← カンマ区切り指定 LETSENCRYPT_EMAIL: mail@example.com networks: default: external: name: shared
- nginx側のdocker-compose.yml例
version: "2" services: nginx-proxy: image: jwilder/nginx-proxy container_name: nginx-proxy ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro - /etc/nginx/vhost.d - /usr/share/nginx/html restart: always networks: - shared letsencrypt: image: jrcs/letsencrypt-nginx-proxy-companion container_name: letsencrypt volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./certs:/etc/nginx/certs:rw volumes_from: - nginx-proxy restart: always networks: - shared networks: shared: external: true実行例
事前準備
上記の様にdocker-compose.ymlを分離している場合は事前にDocker networkを作成し同じネットワークを利用する様に指定しておく必要が有る。
docker network create --driver bridge shared
起動
nginx側、自作サービスの両方を起動する
docker-compose up -d
結果
指定した保存ディレクトリ内に以下の様にドメイン名別の証明書が生成される。
どちらのドメイン名でもSSL接続可能となる。example.com.chain.pem example.com.crt example.com.dhparam.pem example.com.key www.example.com.chain.pem www.example.com.crt www.example.com.dhparam.pem www.example.com.key
- 投稿日:2019-02-11T18:12:23+09:00
Dockerを使って機械学習の環境を作ろうとした話
目次
- 目標
- どんな環境作るの?
- Dockerfileの準備
- イメージを作成してコンテナを起動して潜入してみる
- Volumeを指定して、ファイルを同期してみる
- docker-composeで更に楽に作ろう!
- まとめ
目標
- Dockerを実際に触って慣れる
- Dockerを使って環境構築してみる
どんな環境作るの??
まず、今回はDockerを使用して環境構築することが目標なので、そこまで厳密に環境にこだわっていません。
作成する環境は以下です。
python3.7.2をベースに機械学習に使うライブラリを用意していきます。
インストールするのは以下です。
- python 3.7.2
- numpy
- scikit-learn
- pandas
- matplotlib
- pytest
ディレクトリの構成は以下です。
bashsample001. ├── Dockerfile ├── docker-compose.yml ├── pip │ └── requirements.txt ├── src │ └── hello.py └── test以下のhello.pyを先に用意しておきます。
hello.pyprint("hello")requirements.txtの中身は以下です。
本当はverの指定とかをするべきなんでしょうが省略。requirements.txtnumpy pandas matplotlib scikit-learn pytestDockerfileの準備
実際に作って行きましょう。
簡単に言うとDockerfileって何????
Dockerのイメージを作る際に使用する設計書
そして、以下が作成したDockerfileです。
Dockerfile# pythonの3.7.2-slimをベースにする FROM python:3.7.2-slim # ARGで変数を定義 # buildする時に変更可能 # コンテナ内のディレクトを決めておく ARG root_directory=/sample001 # python3 pipのインストール RUN apt-get update && apt-get install -y \ python3 \ python3-pip \ # imageのサイズを小さくするためにキャッシュ削除 && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ # pipのアップデート && pip install --upgrade pip # Dockerfileを実行したディレクトにあるファイルを全てイメージにコピー COPY . ${root_directory}/ # 機械学習に使用するライブラリのインストール WORKDIR ${root_directory}/pip/ RUN pip install -r requirements.txt # ディレレクトリの移動 WORKDIR ${root_directory}今回はimageのサイズの削減にも取り組んだので、以下のことをしています。
- -slimを使用
- Runコマンドは一つにまとめる
- キャッシュの削除
詳しくは、こちらに載っています。
http://docs.docker.jp/engine/userguide/eng-image/dockerfile_best-practice.html#build-cache
イメージを作成,コンテナを起動して潜入してみる
buildで用意したDockerfileからイメージを作成します。
作成したイメージが確認しやすいように、名前を付けてbuildしています。
lang:bash
docker build ./ -t python_image
イメージが作成されているか確認
bash$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE python_image latest 8c9cc96fbb5a About a minute ago 580MB python 3.7.2-slim 12c44ed85032 5 days ago 143MBイメージが作成されていることが確認出来たので
これを基にしてコンテナを作成します。bash$ docker run -it --rm --name python_container python_image /bin/bash使用しているオプションの説明
- -i:ホストマシンとコンテナの双方向に接続できるようにするため
- --rm:コンテナから抜けるとコンテナを削除
- -t:コンテナ内に擬似的なターミナルを割り当て
- -name:コンテナに名前を付ける
最後の/bin/basはターミナルの起動のために追加
コンテナの内部に入ると以下のように表示されます。
bash$ docker run -it --rm --name python_container python_image /bin/bash root@0e86c2a3cfcb:/sample001#この状態で別のターミナルを開いてコンテナの確認をしましょう。
docker ps
で現在稼働中のコンテナのみを確認ができます。bash$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0e86c2a3cfcb python_image "/bin/bash" 3 minutes ago Up 3 minutes python_containerコンテナ内部に潜入できたので、実際にpythonを動かしてみましょう!
bashroot@759f6d3f586a:/sample001# python src/hello.py hello root@759f6d3f586a:/sample001#これでpythonの実行環境は構築できました。
ただし、一つ開発していく上で不便なことがあります。
作成したhello.pyを編集して再度、コンテナ上で実行してみます。hello.pyprint("hello") print("world")bashroot@759f6d3f586a:/sample001# python src/hello.py hello root@759f6d3f586a:/sample001# python src/hello.py hello root@759f6d3f586a:/sample001#編集したはずの内容が反映されていません。
これを解決するのが次の項目です。Volumeを指定して、ファイルを同期してみる
話は一旦、Dockerfileに戻ります。
Dockerfileの中に、以下のコードがありました。Dockerfile# Dockerfileを実行したディレクトにあるファイルを全てイメージにコピー COPY . ${root_directory}/buildをする際にイメージの中にファイルを含めています。
つまり、このイメージをコンテナ化してもイメージに含まれているファイルしかコンテナには存在しないのです。
ホストマシンで編集した内容が、即時コンテナにも反映されるようにするには以下のコマンドでコンテナを立ち上げます。
bash$ docker run -it --rm -v $PWD/src:/sample001/src --name python_container python_image /bin/bash
$ docker run -v #{ホストマシンの任意のディレクトリ}:#{Dockerコンテナ内の任意のディレクトリ}
これでホストマシンとコンテナの同期が完了しました。
実際に編集して試してみました。bash$ docker run -it --rm -v $PWD/src:/sample001/src --name python_container python_image /bin/bash root@a2a0a825ef79:/sample001# cd src root@a2a0a825ef79:/sample001/src# python hello.py hello root@a2a0a825ef79:/sample001/src# python hello.py hello world root@a2a0a825ef79:/sample001/src#これで環境ができましたね!!ようやく開発に移れる。
あとは、毎回コンテナを立ち上げる時に以下を打ち込んでと。。。bashdocker run -it --rm -v $PWD/src:/sample001/src --name python_container python_image /bin/bashこれ、もう少し楽に記述できないかな??
次の項目へdocker-composeで更に楽に作ろう!
開発環境を、もっと楽に立ち上げる為に以下のファイルを用意します。
docker-composeversion: "3" services: app: container_name: "python_app" build: context: . dockerfile: ./Dockerfile image: python_ml:3.7.2 volumes: - $PWD/src:/sample001/src - $PWD/test:/sample001/test ports: - 80:80 tty: true簡単に言うとdocker-composeって何?????
複数のコンテナを同時に立ち上げてくれるもの。
オプションを記述することで各コンテナの起動時の設定などができる。
今回は複数のコンテナではないですが、起動時のオプションをこちらに持たせておくことにしましょう。
docker-composeのあるディレクトリに移動して
以下のコマンドでイメージの作成からコンテナの起動まで全て行ってくれます。bash$ docker-compose up -dあとはコンテナの内部に以下のコマンドで入ります。
docker exec -it python_app /bin/sh -c "[ -e /bin/bash ] && /bin/bash || /bin/sh"
まとめ
Dockerを使って、機械学習用の環境が構築できました。
docker-composeの説明が、自分の中で纏まっていないので纏まり次第追記していく予定です。
説明不足な所や、間違った所は指摘していただけると助かります。
- 投稿日:2019-02-11T14:57:50+09:00
Dockerコンテナとボリュームを圧縮ファイルにバックアップする
はじめに
AWS ECS
などのマネージド環境ではなくて、自前でDocker
(およびdocker-compose
)を運用している場合のバックアップの取得方法について、自分自身のメモのために残しておきます。環境
例えば、以下のように
wordpress
とmysql
コンテナをdocker-compose
で管理しているとします。version: '3.2' services: wordpress: image: wordpress restart: always ports: - 80:80 mysql: image: mysql:5.7 restart: always volumes: - /var/lib/mysql command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci ports: - 3306:3306そして、以下のようなディレクトリ構造をもっているとします。
backup
:Docker
コンテナとボリュームのバックアップが格納されるbin
: バックアップ用のスクリプトが配置されている$ tree -d -L 3 . ├── app ├── backup │ ├── containers │ │ └── YYYY-MM-DD │ └── volumes │ └── YYYY-MM-DD ├── bin ...ボリュームのバックアップ
最終的に以下のようなスクリプトになりました。
バックアップをとるために、docker
の公式ドキュメント1ではubuntu
コンテナを使っていますが、tar
コマンドを使えればいいので、より軽量なalpine
コンテナを使うようにしました。#!/usr/bin/env bash # bin/backup_volumes.sh CURRENT_DIRECTORY=$(dirname "$0") BACKUP_DIR="backup/volumes" cd "$CURRENT_DIRECTORY"/../ LOCAL_BACKUP_PATH="$(pwd)/$BACKUP_DIR/$(date '+%Y-%m-%d')" rm -rf "$LOCAL_BACKUP_PATH" mkdir -p "$LOCAL_BACKUP_PATH" CONTAINER_PREFIX=$(basename $(pwd)) docker run --rm --volumes-from $(docker ps -q -f name="$CONTAINER_PREFIX"_mysql) -v "$LOCAL_BACKUP_PATH":/backup alpine tar cvf /backup/mysql_volumes.tar /var/lib/mysql docker run --rm --volumes-from $(docker ps -q -f name="$CONTAINER_PREFIX"_wordpress) -v "$LOCAL_BACKUP_PATH":/backup alpine tar cvf /backup/wordpress_volumes.tar /var/www/html
bin/backup_volumes.sh
を実行すると、backup/volumes/YYYY-MM-DD
配下にバックアップファイルが作成されます。$ bin/backup_volumes.sh $ ls backup/volumes/YYYY-MM-DD mysql_volumes.tar wordpress_volumes.tarコンテナのバックアップ
最終的に以下のようなスクリプトになりました。
ほぼほぼ、Docker
の公式ドキュメント2のとおりとなりました。#!/usr/bin/env bash # bin/backup_containers.sh CURRENT_DIRECTORY=$(dirname "$0") BACKUP_DIR="backup/containers" cd "$CURRENT_DIRECTORY"/../ LOCAL_BACKUP_PATH="$(pwd)/$BACKUP_DIR/$(date '+%Y-%m-%d')" rm -rf "$LOCAL_BACKUP_PATH" mkdir -p "$LOCAL_BACKUP_PATH" CONTAINER_PREFIX=$(basename $(pwd)) docker export $(docker ps -q -f name="$CONTAINER_PREFIX"_mysql) > "$LOCAL_BACKUP_PATH/mysql_container.tar" docker export $(docker ps -q -f name="$CONTAINER_PREFIX"_wordpress) > "$LOCAL_BACKUP_PATH/wordpress_container.tar"
bin/backup_containers.sh
を実行すると、backup/containers/YYYY-MM-DD
配下にバックアップファイルが作成されます。$ bin/backup_containers.sh $ ls backup/volumes/YYYY-MM-DD mysql_container.tar wordpress_container.tarおわりに
これで、
mysql
データベースとwordpress
のソースコード、設定ファイル、プラグイン、添付ファイルをバックアップすることができました。
できれば、マネージドなDocker
環境を使いたいところですが、仕方なく自分で運用する場合は、もしもの事態に備えてバックアップをとるようにしておきましょう。
ではでは。
- 投稿日:2019-02-11T13:18:54+09:00
DockerでOracle11gを構築する
はじめに
とある事情にてOracle11gの環境が必要になりました。
手持ちのMacBook1台で開発環境をFIXさせたいため、Dockerにて構築することにしました。前準備
- Dockerは導入済みとします。
Docker for Macをインストールしてみた が非常にわかりやすいと思います。- Oracle.comのアカウントは作成済みとします。
まだの方は Oracleプロファイルの作成 から作成します。構築作業
GitHubからOracleのDockerイメージをダウンロードする
$ git clone https://github.com/oracle/docker-images.gitOracle本体をダウンロードする
Oracleのダウンロードサイトから、Oracle本体をダウンロードする必要があります。
今回は11gの「Linux x86-64」からダウンロードしてきます。Oracle本体をDockerイメージに配置する
Dockerで動かすOracleはシングル構成とRac構成が選択できます。
今回構築する環境はシングル構成とします。ダウンロードしたOracle本体をzipファイルのまま、Dockerイメージにコピーします。
docker-images/OracleDatabase/SingleInstance/dockerfiles/に各バージョンごとにディレクトリがありますので、Oracle本体と対応したディレクトリに配置する必要があります。
11g以降のバージョンがDockerで利用できることがわかりますね。$ ll docker-images/OracleDatabase/SingleInstance/dockerfiles/ total 16 drwxr-xr-x 8 oracle staff 256 2 10 19:22 ./ drwxr-xr-x 10 oracle staff 320 2 10 15:53 ../ drwxr-xr-x 9 oracle staff 288 2 10 16:09 11.2.0.2/ drwxr-xr-x 18 oracle staff 576 2 10 15:53 12.1.0.2/ drwxr-xr-x 16 oracle staff 512 2 10 15:53 12.2.0.1/ drwxr-xr-x 16 oracle staff 512 2 10 15:53 18.3.0/ drwxr-xr-x 8 oracle staff 256 2 10 15:53 18.4.0/ -rwxr-xr-x 1 oracle staff 5088 2 10 15:53 buildDockerImage.sh*イメージをビルドする
buildDockerImage.shを叩いてイメージをビルドします。
コンソールに「Successfully tagged oracle/database:11.2.0.2-xe」と出ればOKです。$ docker-images/OracleDatabase/SingleInstance/dockerfiles/buildDockerImage.sh -v 11.2.0.2 -x -i (中略) Successfully built 763f697f8cfb Successfully tagged oracle/database:11.2.0.2-xe Oracle Database Docker Image for 'xe' version 11.2.0.2 is ready to be extended: --> oracle/database:11.2.0.2-xe Build completed in 120 seconds.コンテナを起動する
コンテナの起動直後にOracleのSYSユーザとSYSTEMユーザのパスワードがコンソールに表示されます。
コンソールログがガンガン流れるため、見失わないようにしましょう。$ sudo docker run -p 1521:1521 --shm-size=1g --name oracle11 oracle/database:11.2.0.2-xe ORACLE PASSWORD FOR SYS AND SYSTEM: XXXXXXXXXXXXXX以下のメッセージがコンソールに表示されたら、Oracleが利用できる状態となります。
######################### DATABASE IS READY TO USE! #########################この後も処理が続き、私の環境では結構エラーが出ていましたが、無視しても問題ありませんでした。
起動確認
SQLPlusを使用して、作成したOracleDatabaseに接続してみます。
$ sqlplus system@localhost:1521 SQL*Plus: Release 12.2.0.1.0 Production on Mon Feb 11 13:13:27 2019 Copyright (c) 1982, 2017, Oracle. All rights reserved. Enter password: Connected to: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production SQL>できました!!!
- 投稿日:2019-02-11T13:10:26+09:00
dockerでnginx-proxy使用時の503エラー
久しぶりに投稿するとタイトルに悩む・・・
エラー現象
jwilder/nginx-proxy
を使用してドメインごとにコンテナ振り分けようとしたときに503エラーが出た結論
先に原因書くと自分で
DockerFile
書いているときは、ファイル内にEXPOSE 80
書かないとプロキシに認識されない。経緯
1. エラー発生
ブラウザから見て503出たのでログを確認したところ、下記になっていた。
no live upstreams while connecting to upstream, client: *.*.*.*, server: domain.com, request: "GET / HTTP/2.0", upstream: "http://domain.com/", host: "domain.com", referrer: "https://domain.com/"
2. 原因調査
幸いにもすでに稼働中のほぼ同じ環境が手元にあったので比較しながら調査。
・確認項目
1. アプリ側のコンテナに入って、curl http://localhost
→ OK
2.docker ps
の内容比較 → NG:portsの記載が違う正しい環境だと
80/tcp
があるのに問題環境だと何も記載がない3. 原因
今回勉強がてら、centos7からhttpdとphpをまとめたDockerFileを作ってたんですがそこに
EXPOSE 80
がなかったのでエラーが出ていました。
開発環境だとdocker-compose.yml
にポート指定書いていたんで気づくのが遅れました・・・
- 投稿日:2019-02-11T12:54:31+09:00
docker-composeでよく使うコマンド
背景
docker-composeを雰囲気で使っているのでコマンドの意味を再確認する意味もかねて記事を作成
docker-composeとは
yaml形式の設定ファイルで複数コンテナを実行を一括で管理できるツール
インストールなどは別記事をご参照ください。
Docker Compose のインストール環境
$ docker --version Docker version 18.09.1, build 4c52b90 $ docker-compose --version docker-compose version 1.22.0, build f46880fとりあえずhelp
buildやup,down等の基本コマンド以外を打つときはまずhelp見ます。
これでもわからなければネットなどで調べてます。$ sudo docker-compose help Define and run multi-container applications with Docker. Usage: docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...] docker-compose -h|--help Options: -f, --file FILE Specify an alternate compose file (default: docker-compose.yml) -p, --project-name NAME Specify an alternate project name (default: directory name) --verbose Show more output --log-level LEVEL Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) --no-ansi Do not print ANSI control characters -v, --version Print version and exit -H, --host HOST Daemon socket to connect to --tls Use TLS; implied by --tlsverify --tlscacert CA_PATH Trust certs signed only by this CA --tlscert CLIENT_CERT_PATH Path to TLS certificate file --tlskey TLS_KEY_PATH Path to TLS key file --tlsverify Use TLS and verify the remote --skip-hostname-check Don't check the daemon's hostname against the name specified in the client certificate --project-directory PATH Specify an alternate working directory (default: the path of the Compose file) --compatibility If set, Compose will attempt to convert deploy keys in v3 files to their non-Swarm equivalent Commands: build Build or rebuild services bundle Generate a Docker bundle from the Compose file config Validate and view the Compose file create Create services down Stop and remove containers, networks, images, and volumes events Receive real time events from containers exec Execute a command in a running container help Get help on a command images List images kill Kill containers logs View output from containers pause Pause services port Print the public port for a port binding ps List containers pull Pull service images push Push service images restart Restart services rm Remove stopped containers run Run a one-off command scale Set number of containers for a service start Start services stop Stop services top Display the running processes unpause Unpause services up Create and start containers version Show the Docker-Compose version informationビルド
サービスをビルドします。
サービス名を指定してビルドすることもできます。
「--no-cache」等も指定できます。$ sudo docker-compose build ## サービスを指定してビルド $ sudo docker-compose build nginx ## Usage Usage: build [options] [--build-arg key=val...] [SERVICE...] Options: --compress Compress the build context using gzip. --force-rm Always remove intermediate containers. --no-cache Do not use cache when building the image. --pull Always attempt to pull a newer version of the image. -m, --memory MEM Sets memory limit for the build container. --build-arg key=val Set build-time variables for services.起動/停止/再起動
up,downでサービスの起動停止を行います。
downとstopの違いは公式より下記のように記載されています。
downは「コンテナ・ネットワーク・イメージ・ボリュームの停止と削除」
stopは「サービスの停止」# 起動 $ sudo docker-compose up ## バックグラウンド実行なら「-d」を付けてup $ sudo docker-compose up -d ## サービスを指定して起動するなら $ sudo docker-compose up nginx # 停止 $ sudo docker-compose stop ## 停止かつコンテナを削除 $ sudo docker-compose down ## イメージも合わせて削除 $ sudo docker-compose down --rmi all # 再起動 $ sudo docker-compose restartyamlの確認
docker-compose.ymlで書かれてる内容が表示されます。
どのようなサービスで構成されているか確認するオプション「--service」もあります。
書き方に誤りがあるときはエラーを出力してくれます。
up前に確認したりするのに使ってます。$ sudo docker-compose config services: db: image: postgres web: build: context: /root/work/docker-compose command: python manage.py runserver 0.0.0.0:8000 depends_on: - db ports: - 8000:8000/tcp volumes: - /root/work/docker-compose:/code:rw version: '2.0' ## サービス名だけ取得 $ docker-compose config --service db web ## エラーがあるとき $ sudo docker-compose config ERROR: yaml.scanner.ScannerError: while scanning a simple key in "./docker-compose.yml", line 14, column 3 could not find expected ':' in "./docker-compose.yml", line 15, column 1create
構築されたサービスを参考にそのコンテナを作ります。
ここで作られたコンテナは起動している状態ではありません。
これもまた引数にサービス名を指定して、特定のサービスだけのコンテナを作ることも可能です。$ docker-compose create Creating db_1 Creating web_1 ## サービス名を指定 $ sudo docker-compose create dbevents
コンテナからのイベントを受信します。
$ docker-compose events ## Usage Usage: exec [options] [-e KEY=VAL...] SERVICE COMMAND [ARGS...] Options: -d, --detach Detached mode: Run command in the background. --privileged Give extended privileges to the process. -u, --user USER Run the command as this user. -T Disable pseudo-tty allocation. By default `docker-compose exec` allocates a TTY. --index=index index of the container if there are multiple instances of a service [default: 1] -e, --env KEY=VAL Set environment variables (can be used multiple times, not supported in API < 1.25) -w, --workdir DIR Path to workdir directory for this command.exec
docker exec
コマンドと同等のことができます。
引数にサービス名と実行するコマンドを指定して実行します。$ docker-compose exec web /bin/bashimages
対象のイメージの情報を表示します。
$ sudo docker-compose images Container Repository Tag Image Id Size -------------------------------------------------------------------------- docker-compose_db_1 postgres latest 5a02f920193b 298 MB docker-compose_web_1 docker-compose_web latest 1b7d48087d77 870 MBkill
コンテナを強制停止します。
シグナルを指定して送ることも可能です。## usage Force stop service containers. Usage: kill [options] [SERVICE...] Options: -s SIGNAL SIGNAL to send to the container. Default signal is SIGKILL. $ sudo docker-compose kill Killing rails5product_web_1 ... done Killing rails5product_db_1 ... donelogs
サービスのログを出力します。
また引数でサービス名を指定できるので、そうするとサービスごとにログを出力してくれます。$ docker-compose logs ## ログをリアルタイム追跡(tailfのように出力「-t」で時間も) $ sudo docker-compose logs -ft db_1 | 2019-02-11T02:21:46.417460752Z The database cluster will be initialized with locale "en_US.utf8". db_1 | 2019-02-11T02:21:46.417466610Z The default database encoding has accordingly been set to "UTF8". db_1 | 2019-02-11T02:21:46.417487267Z The default text search configuration will be set to "english".pause
サービスを一旦停止します。
勿論サービスごとに一時停止も可能です。$ docker-compose pause Pausing db_1 ... done Pausing web_1 ... doneport
割り当てているポートを表示します。引数でサービス名とポート番号が必要になります。
tcp,udpでプロトコルの指定も可能です。## usage Usage: port [options] SERVICE PRIVATE_PORT Options: --protocol=proto tcp or udp [default: tcp] --index=index index of the container if there are multiple instances of a service [default: 1] $ sudo docker-compose port web 3000 0.0.0.0:3000ps
コンテナの一覧を表示します。
$ sudo docker-compose ps Name Command State Ports ------------------------------------------------------------------------- docker-compose_db_1 docker-entrypoint.sh postgres Up 5432/tcp docker-compose_db_2 docker-entrypoint.sh postgres Up 5432/tcp docker-compose_web_1 python manage.py runserver ... Exit 2 ## サービス名でも確認できます $ sudo docker-compose ps web Name Command State Ports ---------------------------------------------------------------------- docker-compose_web_1 python manage.py runserver ... Exit 2pull
サービスのイメージをプルしてきます。
$ sudo docker-compose pull ## Usage Usage: pull [options] [SERVICE...] Options: --ignore-pull-failures Pull what it can and ignores images with pull failures. --parallel Deprecated, pull multiple images in parallel (enabled by default). --no-parallel Disable parallel pulling. -q, --quiet Pull without printing progress information --include-deps Also pull services declared as dependenciesrm
停止中のコンテナを削除します。
起動中のコンテナも削除するならば「-f」を指定してください$ sudo docker-compose rm ## 強制削除 $ sudo docker-compose rm -fscale
サービスを実行するコンテナ数を指定します
$ sudo docker-compose scale db=2 WARNING: The scale command is deprecated. Use the up command with the --scale flag instead. Starting docker-compose_db_1 ... done Creating docker-compose_db_2 ... doneこちらは現在は非推奨とのこと。コメントありがとうございます。
Docker Compose 1.13.0から「scale」が非推奨になり、「up --scale」にtop
各コンテナのプロセス情報を表示します。
$ sudo docker-compose top docker-compose_db_1 UID PID PPID C STIME TTY TIME CMD ---------------------------------------------------------------------------------------------- logstash 15251 14858 0 11:21 ? 00:00:00 postgres: stats collector logstash 15252 14858 0 11:21 ? 00:00:00 postgres: logical replication launcher docker-compose_db_2 UID PID PPID C STIME TTY TIME CMD ---------------------------------------------------------------------------------------------- logstash 28206 28009 0 11:46 ? 00:00:00 postgres: stats collector logstash 28207 28009 0 11:46 ? 00:00:00 postgres: logical replication launcherまとめ
とりあえずこれ使えれば問題あっても調査の足掛かりにはなると思う。
参考リンク
公式リファレンス
docker-composeを使うと複数コンテナの管理が便利に
docker-compose コマンドまとめ
- 投稿日:2019-02-11T09:53:13+09:00
.NetCoreをRaspberry Pi上のdockerでパッと動かすPiBakeryレシピ
.NetCoreをRaspberry Pi上のdockerでパッと動かしたい
Announcing .NET Core 2.1 | .NET Blogでアナウンスされたように、.NetCore2.1からAlpineLinuxとARM32がサポートされた。これにより、Raspberry Piのdocker上で.NetCoreを動作させることが可能になった。PiBakeryを使って、docker上で動く.NetCoreの環境をRaspberry Pi上に作ってみる。
PiBakery?
Raspberry PiはOSインストールがちょっと面倒だ。PiBakeryを使えばScratch風のGUIで簡単にセットアップの手順を設定し、ボタン1つでSDカードに書き込みできる。書き込み終わったSDカードをRaspberry Piにセットし、電源を入れればセットアップが全て完了するという優れものだ。Wifiの設定もできるので外付けのキーボードもマウスもつけなくても、即ssh接続が可能になる。じゃあどうせならPiBakeryで、.NetCoreが動くところまで一気に作ってみよう!ということでやってみた。
PiBakeryレシピの作成
今回最終的に作ったものはこちら。
動作確認環境Raspberry Pi: Raspberry Pi 3 Model B+ OS: Raspbian Lite (stretch) Release: 9.3 HostOS: Windows 10 Pro (64bit) PiBakery: v0.3.81. 基本のセットアップ
PiBakeryを使ってRaspberryPi Zero Wをヘッドレスでセットアップする
こちらの記事を参考にさせて頂きサクッと。こいつをベースに肉付けしていく。※最近のバージョンのPiBakeryではdhcpcdの再起動処理がコメントアウトされていて、後ろのブロックにインターネット接続する処理があるとうまくいかなかった。コメントアウトされている以下の処理をSetup Wifi の後ろにRunCommandで書けば再起動される。
systemctl daemon-reload && sleep 5 systemctl restart dhcpcd && sleep 52. IPアドレス設定
固定IPをRapsberryPiに振る。/etc/dhcpcd.confにstatic ipの情報を追記するため、以下のアドレスを適切に書き換えてPiBakeryのRunCommandで追加。
echo "interface wlan0" >> /etc/dhcpcd.conf # eth0(LAN cable) or wlan0(wifi) echo "static ip_address=192.168.xxx.xxx/24" >> /etc/dhcpcd.conf echo "static routers=192.168.xxx.xxx" >> /etc/dhcpcd.conf echo "static domain_name_servers=192.168.xxx.xxx" >> /etc/dhcpcd.conf[参考]
3. raspi-config(非対話モードで実行)
raspi-configを非対話モードで実行し、ロケールやメモリ節約の設定を行っておく。
## locale sudo raspi-config nonint do_change_locale ja_JP.UTF-8 ## timezone sudo raspi-config nonint do_change_timezone Asia/Tokyo ## wifi country sudo raspi-config nonint do_wifi_country JP ## Save memory usage ### Memory for GPU sudo raspi-config nonint do_memory_split 16 ### Disable Camera sudo raspi-config nonint do_camera 1[参考]
- Raspbianのインストールと最強の初期設定 | 純規の暇人趣味ブログ
- raspi-configをコマンドラインで実行する。 | ラズパイ好きの日記
- Raspberry Piのメモリーを節約する | ものづくりエクスペリメント
4. Docker環境構築
以下をPiBakeryのコマンドとして追加。
# curlでdockerのinstallスクリプトを実行 curl -sSL https://get.docker.com | sh # sudo権限なくてもdockerコマンド使えるようにdockerグループにpiユーザーを追加 sudo usermod -aG docker pi # 再起動 sudo systemctl daemon-reload sudo systemctl restart docker[参考]
5. .NetCoreイメージの取得
.Net Core 2.1 の SDK と Runtime イメージをpull。他にもほしいイメージがあれば同様に取得できる。
docker pull microsoft/dotnet:2.1-runtime docker pull microsoft/dotnet:2.1-sdk[参考]
まとめ
Run Command
がずらずらと並ぶ結果になったので正直普通にシェルスクリプトを書いてそれを呼ぶように工夫するほうが良いと思う。もしくは、PiBakeryには自作のblockを登録する仕組みがあるので、自作ブロックを作っても良い。→作ってみた。このあとは作成した.NetCoreアプリをスムーズに今回用意したRaspberry Pi上にデプロイし、リモートデバッグできるようにしたいが、とりあえず今回はここまで。
- 投稿日:2019-02-11T02:09:50+09:00
dockerで作った環境(nginx+php-fpm+mysql)にLaravelを入れたときの設定メモ
nignxとphp-fpmとmysqlの連携環境をdocker-composeで構築済。しかし、nginxの設定が足りていないので設定を修正する必要がある。
前提
nginxはド素人。PHP(Laravel)の環境を作る必要があり、使ったことが無いnginxで動かしてみようという軽いノリで始めたメモ。
(dockerで)nginxに関するメモ、(dockerで)php-fpmに関するメモ、(dockerで)mysqlに関するメモ、(dockerで作った環境に)Laravelプロジェクトを設置したメモ。
./docker/nginx.conf
nginx.conf(一部)... location /projLaravel/public { try_files $uri $uri/ /projLaravel/public/index.php?$query_string; } ...通常は /projLaravel/public をドキュメントルートにするんだろうけど今回は敢えてしない。重要なのは、 Laravelのプロジェクトでは全てのアクセスを index.php(フロントコントローラ)に集めなければならない と言うこと。 Apacheの場合は.htaccessで行っている。
この設定についてはLaravelのインストール手順を見ると載っている。
- 投稿日:2019-02-11T01:53:16+09:00
Docker for Windowsが起動してくれないので、処方箋を調べて色々試してみた
前書き
最近はDocker動かすのにあまり環境を選ばなくなって、便利になってきました。
しかし、Macでは比較的安定してるDockerさん、Windowsでは未だかなり不安定です。
この度GPD WIN 2にDocker for Windowsをセットアップしてみたのですが、落ちる落ちる、というか一度たりともまともに起動できない、、?
今回こちらを動かせるようにできましたので、レポートをまとめます。
皆さん参考にしていただければ幸いです。
tl;dr
C:\Program Files\Docker\Docker\resources
配下のPowerShellスクリプトから、-ComputerName localhost
というキーワードを全て削除する- 同フォルダで
MobyLinux.ps1 -destroy && MobyLinux.ps1 -create
を実行する- Windowsを再起動する
まずは普通にインストールしてみる
64bit版 の Windows 10 Proか、それ以上のエディション 前提です。Homeな方はマイクロソフトにお布施して、Proへ昇格してください。
32bit版や8.1以前な方、、アップグレードするか、Docker Toolboxで幸せになりましょう。
PS Admin> chohco install -y docker-desktop私のPCではChocolateyをインストールしてるので、管理者権限のPowerShellでサクッとインストールしてしまいます。
結果
赤面すれば許してくれるとでも思ったのでしょうか、このポンコツクジラめ、、?
少なくとも私のGPD WIN 2では一度も起動してくれませんでした。
Docker for WindowsとHyper-Vの再インストール
まず手始めに基本から、ということでDocker for WindowsとHyper-Vを再インストールします。順番は必ず次の順序で行います。
手順
- Docker for Windowsのアンインストール
- Hyper-Vのアンインストール
- Hyper-Vのインストール
- Docker for Windowsのインストール
Docker for WindowsはHyper-Vに依存しているためです。この順番を間違える、、例えばHyper-Vから先にアンインストールすると、こうなります。
Hyper-Vの再インストール
コマンドごとに再起動が必要なので注意。
<# アンインストール(無効化) #> PS Admin> Disable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All <# インストール(有効化) #> PS Admin> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
結果: 変化なし。
ついでなので、Docker for Windowsのリセットも試しましたが駄目です。
Docker ErrorActionPreference
辺りのワードでググってると、いくつか記事が出てきたので試してみます。
Hyper-Vにおける制御フローガードが悪さしている可能性
まず一つ目はHyper-Vのvmcompute.exeに制御フローガードがかかって死ぬ可能性。
“Windowsセキュリティ アプリ” を起動し、次の通りに遷移します。
- アプリとブラウザー コントロール
- Exploit protection の設定 (かなり下のほうにあります)
- プログラム設定 タブ
- C:\WINDOWS\System32\vmcompute.exe > 編集
すると、“制御フローガード (CFG)” の設定がありますので、“☑ システムの上書き” のチェックを外して、適用ボタンを押します。
管理者権限が必要な操作のため、UACが出る場合があるので、必要に応じて昇格してからWindowsを再起動します。
それからDocker for Windowsを動かしてみた結果がこちらです!
、、よろしい、ならば戦争ですね?
コマンドで強制的に起動させる
次にググって見つけたのが、コマンドで強制的にDocker for Windowsを立ち上げている記事。
コマンド
PS Admin> cd "C:\Program Files\Docker\Docker\resources" <# Docker for Windows用Dockerサーバーを破棄 #> PS Admin> .\MobyLinux.ps1 -destroy <# Docker for Windows用Dockerサーバーを作成 #> PS Admin> .\MobyLinux.ps1 -create
結果
.\MobyLinux.ps1 : このシステムではスクリプトの実行が無効になっているため、ファイル C:\Program Files\Docker\Docker\resources\MobyLinux.ps1 を読み込むことができません。詳細については、「about_Execution_Policies」
(https://go.microsoft.com/fwlink/?LinkID=135170) を参照してください。ですよねー?
PowerShellスクリプトは、デフォでは実行禁止です。
そこで、少しコマンドに細工を加えます。
PS Admin> cd "C:\Program Files\Docker\Docker\resources" <# Docker for Windows用Dockerサーバーを破棄 #> PS Admin> powershell -NoProfile -ExecutionPolicy Unrestricted .\MobyLinux.ps1 -destroy <# Docker for Windows用Dockerサーバーを作成 #> PS Admin> powershell -NoProfile -ExecutionPolicy Unrestricted .\MobyLinux.ps1 -create
これでPowerShellスクリプトが動きました。
ただこれでも一筋縄ではいきません。Hyper-V\Get-VMHost : Hyper-V で、コンピューター 'localhost' 上のオブジェクトにアクセスしようとしましたが、オブジェクトが見つからずエラーが発生しました。オブジェクトは削除された可能性があります。仮想マシン管理サービスがコンピューター上で実行されていることを確認してください。
一体何なのでしょう。。
VHDXのあるフォルダのアクセス権限を取得する
記事では続きがあって、
C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks\
上記フォルダを開くとあります。
エクスプローラーで開いてみる
試しにURLをエクスプローラーに貼ってみましたが、そのままでは開けないようなので、“パブリックのドキュメント”から辿ってみます。
すると怪しげなダイアログが、、
アクセス周りでしょうか。権限を取得した状態でもう一度コマンドを実行します。
Hyper-V\Get-VMHost : Hyper-V で、コンピューター 'localhost' 上のオブジェクトにアクセスしようとしましたが、オブジェクトが見つからずエラーが発生しました。オブジェクトは削除された可能性があります。仮想マシン管理サービスがコンピューター上で実行されていることを確認してください。
だめですか。。?
下記コマンドを実行してから再起動する、という策もググっていたら出てきましたが、こちらも特に効果なしのようです。
PS Admin> mofcomp %SYSTEMROOT%\System32\WindowsVirtualization.V2.mof
localhost
につながらない?ここでちょっと思い当たることがありまして、下記コマンドを叩いてみました。
PS Admin> Hyper-V\Get-VMHost -ComputerName localhost
Hyper-Vの仮想マシンホスト一覧を取得する関数です。結果は下記の通りでした。
Hyper-V\Get-VMHost : Hyper-V で、コンピューター 'localhost' 上のオブジェクトにアクセスしようとしました
が、オブジェクトが見つからずエラーが発生しました。オブジェクトは削除された可能性があります。仮想マシン管理サービスがコンピューター上で実行されていることを確認してください。やはり先程と同じエラーメッセージです。
PC名の指定を外してみる
PS Admin> Hyper-V\Get-VMHost
Name LogicalProcessorCount MemoryCapacity(M) VirtualMachineMigrationEnabled ---- --------------------- ----------------- ------------------------------ DESKTOP-xxxxxxx 4 8110.25390625 False
正しい値が取れるようになりました!
ということで、この辺をヒントに再度ググってみたところ、Docker for WindowsのIssueを発見。
I solved it by removing the "-ComputerName" for all commands listed in the file MobyLinux.ps1 in the "function New-MobyLinuxVM { }" and it worked.
ほう。
Docker for WindowsのPowerShellスクリプトを編集する
ということで、不本意ですが、配下フォルダにあるPowerShellスクリプトのうち、
Hyper-V\Get-VMHost -ComputerName localhost
を含むコードを探して、Hyper-V\Get-VMHost
へ置き換えてみました。
編集したスクリプトで破棄してみる
PS Admin> powershell -NoProfile -ExecutionPolicy Unrestricted .\MobyLinux.ps1 -destroy
Delete VHD C:\Users\Public\Documents\Hyper-V\Virtual Hard Disks\MobyLinuxVM.vhdx
破棄は無事できました!
では生成はどうでしょう、、??
PS Admin> powershell -NoProfile -ExecutionPolicy Unrestricted .\MobyLinux.ps1 -create
Hyper-V\Get-VMHost : Hyper-V で、コンピューター 'localhost' 上のオブジェクトにアクセスしようとしました
が、オブジェクトが見つからずエラーが発生しました。オブジェクトは削除された可能性があります。仮想マシン管理サービスがコンピューター上で実行されていることを確認してください。
?さん、、あなたも粘りますね?
では
Get-VMHost
関係なしに、-ComputerName localhost
という記述をすべて削除してみましょうか。それからまたリトライしてみます。
PS Admin> powershell -NoProfile -ExecutionPolicy Unrestricted .\MobyLinux.ps1 -create
VM created.
、、おおお!?!?
??????
やりました✨
早速動いているか確認すべく、
docker ps
コマンドを叩いてみましょう。
error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.39/containers/json: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.
あれれ、、困ったときはひとまずWindowsを再起動してからリトライしてみましょう。。
ご視聴ありがとうございました。
それにしても、まさかWindowsでDockerを動かすのがここまで大変とは。。
Mac版くらいに安定して動かせる日が来ることを期待したいです。
- 投稿日:2019-02-11T00:49:03+09:00
Step Functions と Lambda をローカルで実行するときのハマりどころ
はじめに
StepFunctions を local で実行するための Docker Image
amazon/aws-stepfunctions-local
が公開されました。
公式チュートリアルにしたがって StepFunctions と Lambda Function をローカルで実行してみたときの手順メモ。
Docker Container を起動するときの環境変数周りでハマりました。。手順
SAM アプリケーションの作成
公式チュートリアルにしたがって、HellorWorldFunction のSAMアプリケーションを作成します。
API のエンドポイントの確認
$ sam local start-apiエンドポイントにアクセスする
$ curl http://127.0.0.1:3000/hello {"message":"hello world"}Lambda Function をローカルで起動する
$ sam local start-lambda 2019-02-11 00:19:31 Found credentials in environment variables. 2019-02-11 00:19:31 Starting the Local Lambda Service. You can now invoke your Lambda Functions defined in your template through the endpoint. 2019-02-11 00:19:31 * Running on http://127.0.0.1:3001/ (Press CTRL+C to quit)Docker コンテナの環境変数を指定する
資料にあるとおり、Dockerイメージに環境変数を与える必要があります。
aws-credentials.txtAWS_ACCOUNT_ID=123456789012 AWS_DEFAULT_REGION=us-east-1 AWS_ACCESS_KEY_ID=dummy AWS_SECRET_ACCESS_KEY=dummy LAMBDA_ENDPOINT=http://host.docker.internal:3001ローカル環境変数を指定
.envrcexport AWS_DEFAULT_REGION=us-east-1 export AWS_REGION=us-east-1 export AWS_ACCOUNT_ID=123456789012 export AWS_ACCESS_KEY_ID=dummy1 export AWS_SECRET_ACCESS_KEY=dummyStepFunctions をローカルで起動
$ docker run -p 8083:8083 --env-file aws-credentials.txt amazon/aws-stepfunctions-localローカルの StepFunctions に state machine を作成する
$ aws stepfunctions --endpoint http://localhost:8083 create-state-machine --definition "{\ \"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Local function\",\ \"StartAt\": \"HelloWorld\",\ \"States\": {\ \"HelloWorld\": {\ \"Type\": \"Task\",\ \"Resource\": \"arn:aws:lambda:us-east-1:123456789012:function:HelloWorldFunction\",\ \"End\": true\ }\ }\ }\ }}" --name "HelloWorld" --role-arn "arn:aws:iam::012345678901:role/DummyRole"StepFunction の実行
$ aws stepfunctions --endpoint http://localhost:8083 start-execution --state-machine arn:aws:states:us-east-1:123456789012:stateMachine:HelloWorld --name test { "executionArn": "arn:aws:states:us-east-1:123456789012:execution:HelloWorld:test", "startDate": 1549812335.58 }StepFunctin の実行状態の確認
$ aws stepfunctions --endpoint http://localhost:8083 describe-execution --execution-arn arn:aws:states:us-east-1:123456789012:execution:HelloWorld:test { "executionArn": "arn:aws:states:us-east-1:123456789012:execution:HelloWorld:test", "stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:HelloWorld", "name": "test", "status": "SUCCEEDED", "startDate": 1549812335.58, "stopDate": 1549812339.711, "input": "{}", "output": "{\"statusCode\":200,\"body\":\"{\\\"message\\\":\\\"hello world\\\"}\"}" }この手順のハマりどころ
ポイントは、Dockerコンテナの起動時の環境変数
LAMBDA_ENDPOINT
をhost.docker.internal
に指定することです。
localhost
に指定すると、Docker コンテナからLocalに接続できないのでConnection Error
になります。
なお、host.docker.internal
というのは Docker コンテナからローカルPCのポートに接続するために用意されたエンドポイントらしいです[4]
。この方法は Docker form Mac/Windows のみ有効のようです。LAMBDA_ENDPOINTをlocalhostにした場合のエラー2019-02-10 14:27:56.514: arn:aws:states:us-east-1:123456789012:execution:HelloWorld:test : {"Type":"LambdaFunctionFailed","PreviousEventId":4,"LambdaFunctionFailedEventDetails":{"Error":"Lambda.SdkClientException","Cause":"Unable to execute HTTP request: Connect to localhost:3001 [localhost/127.0.0.1] failed: Connection refused (Connection refused)"}} 2019-02-10 14:27:56.520: arn:aws:states:us-east-1:123456789012:execution:HelloWorld:test : {"Type":"ExecutionFailed","PreviousEventId":5,"ExecutionFailedEventDetails":{"Error":"Lambda.SdkClientException","Cause":"Unable to execute HTTP request: Connect to localhost:3001 [localhost/127.0.0.1] failed: Connection refused (Connection refused)"}}なお、
LAMBDA_ENDPOINT
の設定をせずに起動した場合はThe security token included in the request is invalid.
という認証系のエラーメッセージとなり、さらに混乱させられました。LAMBDA_ENDPOINT設定されていない場合のエラー2019-02-10 14:25:36.380: arn:aws:states:us-east-1:123456789012:execution:HelloWorld:test1 : {"Type":"LambdaFunctionFailed","PreviousEventId":4,"LambdaFunctionFailedEventDetails":{"Error":"Lambda.AWSLambdaException","Cause":"The security token included in the request is invalid. (Service: AWSLambda; Status Code: 403; Error Code: UnrecognizedClientException; Request ID: bb917ab7-8309-447a-a830-28cbedef8aa1)"}} 2019-02-10 14:25:36.381: arn:aws:states:us-east-1:123456789012:execution:HelloWorld:test1 : {"Type":"ExecutionFailed","PreviousEventId":5,"ExecutionFailedEventDetails":{"Error":"Lambda.AWSLambdaException","Cause":"The security token included in the request is invalid. (Service: AWSLambda; Status Code: 403; Error Code: UnrecognizedClientException; Request ID: bb917ab7-8309-447a-a830-28cbedef8aa1)"}}終わりに
環境変数の設定について、公式チュートリアルには明確な設定内容が書かれてなかったのでけっこうハマりました。。
とにかくこれで、StepFunctionsをローカルから実行することができるようになりました。参考
- 投稿日:2019-02-11T00:45:27+09:00
Dockerコンテナ上でfirebase loginする方法
Dockerコンテナ上でfirebase loginしたときに迷ったところをメモ。
コンテナを起動して表示されたURLからGoogleログインしてアクセス許可すると、
「 http://localhost:9005/?state=... 」にリダイレクトされる。
ローカルでfirebaseが動いているわけじゃないからアクセスできない。# コンテナを起動して docker container run -it firebase bash # firebase loginしてみる firebase login ? Allow Firebase to collect anonymous CLI usage and error reporting information? No Visit this URL on any device to log in: https://accounts.google.com/o/oauth2/auth?... Waiting for authentication... # 上記URLからGoogleログインしてアクセス許可するとlocalhost:9005にリダイレクトされる。。こういう場合はコンテナ側のポート9005を公開してあげれば大丈夫。
docker container run -it -p 9005:9005 firebase bash