- 投稿日:2019-02-28T23:21:09+09:00
プラグインインストール済のJenkins 構築 Docker編 番外編
環境や前提条件
windows10 pro 1803
PowerShell
Docker 18.09.0
jenkins:2.19.4モチベーション
jenkinsのImageをpullしてくると、そのベースになっているlinuxのことを全く意識しなくてよいのだが、気になったので調べてみた。
コンテナにログイン
PS C:\docker\jenkins> docker exec -i -t myjenkins-3 bashディストリビューション名の確認→Debian 8ということがわかる。
jenkins@df7311076006:/$ cat /etc/issue Debian GNU/Linux 8 \n \lDebianのバージョンは8.6
jenkins@df7311076006:/etc$ cat /etc/debian_version 8.6unameでバージョン確認
jenkins@df7311076006:/$ uname -a Linux df7311076006 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 GNU/Linux意味は以下の通り。
- Linux:OS名
- df7311076006:ノード名
- 4.9.125-linuxkit:OSのリリース
- #1 SMP Fri Sep 7 08:20:28 UTC 2018:OSのバージョン
- x86_64:マシンおよびハードウェアの名称
- GNU/Linux
docker historyでImageがどのように作られたかの履歴を確認。
PS C:\docker\jenkins> docker history --no-trunc myjenkins:1 IMAGE CREATED CREATED BY SIZE COMMENT sha256:f61635651954adb853e95690b04dd3791e4fdbcfab7bfb66a2d505e31f3df31c 2 years ago /bin/sh -c #(nop) COPY file:2a6a3e16202b8dddab5edef50f712c16fe8f6980f5aea80c8c76b5db4f903913 in /usr/local/bin/install-plugins.sh 5.96kB <missing> 2 years ago /bin/sh -c #(nop) COPY file:93fb511d485dd2d6060c484dcedb902947875042048de529676a0a0aed27b5a3 in /usr/local/bin/plugins.sh 3.92kB <missing> 2 years ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/tini" "--" "/usr/local/bin/jenkins.sh"] 0B <missing> 2 years ago /bin/sh -c #(nop) COPY file:7eec179a0dd3aad4a9c9290bc4d85e4775c8cf6bc2932527892ca6e87739e474 in /usr/local/bin/jenkins.sh 1.21kB <missing> 2 years ago /bin/sh -c #(nop) COPY file:26c3c5818bc87662d1f4905a3ed73bd55a0a75f731c7dc52d0599c00f51408e9 in /usr/local/bin/jenkins-support 5kB <missing> 2 years ago /bin/sh -c #(nop) USER [jenkins] 0B <missing> 2 years ago /bin/sh -c #(nop) ENV COPY_REFERENCE_FILE_LOG=/var/jenkins_home/copy_reference_file.log 0B <missing> 2 years ago /bin/sh -c #(nop) EXPOSE 50000/tcp 0B <missing> 2 years ago /bin/sh -c #(nop) EXPOSE 8080/tcp 0B <missing> 2 years ago |6 JENKINS_SHA=ea61a4ff86f0db715511d1118a4e2f0a6a0311a1 JENKINS_URL=https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/2.19.4/jenkins-war-2.19.4.war gid=1000 group=jenkins uid=1000 user=jenkins /bin/sh -c chown -R ${user} "$JENKINS_HOME" /usr/share/jenkins/ref 328B <missing> 2 years ago /bin/sh -c #(nop) ENV JENKINS_UC=https://updates.jenkins.io 0B <missing> 2 years ago |6 JENKINS_SHA=ea61a4ff86f0db715511d1118a4e2f0a6a0311a1 JENKINS_URL=https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/2.19.4/jenkins-war-2.19.4.war gid=1000 group=jenkins uid=1000 user=jenkins /bin/sh -c curl -fsSL ${JENKINS_URL} -o /usr/share/jenkins/jenkins.war && echo "${JENKINS_SHA} /usr/share/jenkins/jenkins.war" | sha1sum -c - 69.8MB <missing> 2 years ago /bin/sh -c #(nop) ARG JENKINS_URL=https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/2.19.4/jenkins-war-2.19.4.war 0B <missing> 2 years ago /bin/sh -c #(nop) ARG JENKINS_SHA=ea61a4ff86f0db715511d1118a4e2f0a6a0311a1 0B <missing> 2 years ago /bin/sh -c #(nop) ENV JENKINS_VERSION=2.19.4 0B <missing> 2 years ago /bin/sh -c #(nop) ARG JENKINS_VERSION 0B <missing> 2 years ago /bin/sh -c #(nop) COPY file:c629bc0b9ecb5b7233000c973f65721df4ce1307a5d5b33ac3871ff61a9172ff in /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy 328B <missing> 2 years ago |4 gid=1000 group=jenkins uid=1000 user=jenkins /bin/sh -c curl -fsSL https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-static -o /bin/tini && chmod +x /bin/tini && echo "$TINI_SHA /bin/tini" | sha1sum -c - 823kB <missing> 2 years ago /bin/sh -c #(nop) ENV TINI_SHA=fa23d1e20732501c3bb8eeeca423c89ac80ed452 0B <missing> 2 years ago /bin/sh -c #(nop) ENV TINI_VERSION=0.9.0 0B <missing> 2 years ago |4 gid=1000 group=jenkins uid=1000 user=jenkins /bin/sh -c mkdir -p /usr/share/jenkins/ref/init.groovy.d 0B <missing> 2 years ago /bin/sh -c #(nop) VOLUME [/var/jenkins_home] 0B <missing> 2 years ago |4 gid=1000 group=jenkins uid=1000 user=jenkins /bin/sh -c groupadd -g ${gid} ${group} && useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user} 335kB <missing> 2 years ago /bin/sh -c #(nop) ARG gid=1000 0B <missing> 2 years ago /bin/sh -c #(nop) ARG uid=1000 0B <missing> 2 years ago /bin/sh -c #(nop) ARG group=jenkins 0B <missing> 2 years ago /bin/sh -c #(nop) ARG user=jenkins 0B <missing> 2 years ago /bin/sh -c #(nop) ENV JENKINS_SLAVE_AGENT_PORT=50000 0B <missing> 2 years ago /bin/sh -c #(nop) ENV JENKINS_HOME=/var/jenkins_home 0B <missing> 2 years ago /bin/sh -c apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/* 0B <missing> 2 years ago /bin/sh -c /var/lib/dpkg/info/ca-certificates-java.postinst configure 418kB <missing> 2 years ago /bin/sh -c set -x && apt-get update && apt-get install -y openjdk-8-jdk="$JAVA_DEBIAN_VERSION" ca-certificates-java="$CA_CERTIFICATES_JAVA_VERSION" && rm -rf /var/lib/apt/lists/* && [ "$JAVA_HOME" = "$(docker-java-home)" ] 352MB <missing> 2 years ago /bin/sh -c #(nop) ENV CA_CERTIFICATES_JAVA_VERSION=20140324 0B <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1 0B <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8u111 0B <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 0B <missing> 2 years ago /bin/sh -c { echo '#!/bin/sh'; echo 'set -e'; echo; echo 'dirname "$(dirname "$(readlink -f "$(which javac || which java)")")"'; } > /usr/local/bin/docker-java-home && chmod +x /usr/local/bin/docker-java-home 87B <missing> 2 years ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B <missing> 2 years ago /bin/sh -c echo 'deb http://deb.debian.org/debian jessie-backports main' > /etc/apt/sources.list.d/jessie-backports.list 55B <missing> 2 years ago /bin/sh -c apt-get update && apt-get install -y --no-install-recommends bzip2 unzip xz-utils && rm -rf /var/lib/apt/lists/* 1.29MB <missing> 2 years ago /bin/sh -c apt-get update && apt-get install -y --no-install-recommends bzr git mercurial openssh-client subversion procps && rm -rf /var/lib/apt/lists/* 123MB <missing> 2 years ago /bin/sh -c apt-get update && apt-get install -y --no-install-recommends ca-certificates curl wget && rm -rf /var/lib/apt/lists/* 44.3MB <missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 2 years ago /bin/sh -c #(nop) ADD file:1d214d2782eaccc743b8d683ccecf2f87f12a0ecdfbcd6fdf4943ce616f23870 in / 123MBjavaがopenjdk8.111
JENKINS_HOME=/var/jenkins_home
JENKINS_VERSION=2.19.4
などの設定をしていることがわかる。以上、興味本位で調べてみた。番外編でした。
- 投稿日:2019-02-28T22:53:04+09:00
jupyter/datascience-notebookでPythonのデータ解析環境を構築する
『Software Design 2019年3月号』で「ITエンジニアのための機械学習と微分積分入門」という特集が組まれています。特集の第3章「Pythonで実践する機械学習」ではPythonのコードで簡単なデータ解析のアルゴリズムが解説されています。章の最初にPythonの環境構築の節があり、以下3種類の環境構築の方法が示されています。
- 標準のPythonを使う
- Anaocndaの利用
- Dockerを使う
3番目の「Dockerを使う」方法では、
jupyter/datascience-notebook
を利用すればサンプルコードを全て実行できるとあります。本記事では、
jupyter/datascience-notebook
を使って特集記事のコードを実行する環境を構築する手順をまとめました。環境構築の手順
概要
手順の概要は以下の通りです。
- Dockerをインストールする。
- Dockerイメージを取得する。
- Dockerイメージを実行する。
- データ解析環境にアクセスする。
1. Dockerをインストールする。
最初にDockerをインストールします。
以下はmacOSでHomebrewをインストール済みの場合です。
$ brew cask install docker2. Dockerイメージを取得する。
jupyter/datascience-notebook
のDockerイメージを取得します。$ docker pull jupyter/datascience-notebook
イメージのタグを省略すると、自動的に最新版
jupyter/datascience-notebook:latest
がダウンロードされます。3. Dockerイメージを実行する。
以下のコマンドで取得したイメージを実行します。
$ docker run --rm -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v $(pwd):/home/jovyan/work jupyter/datascience-notebook
-p 10000:8888
はホストの10000ポートをコンテナの8888ポートにマッピングします。
-e JUPYTER_ENABLE_LAB=yes
はコンテナ開始時にjupyter notebook
の代わりにjupyter lab
を実行するオプションです。
-v
オプションではホストのカレントディレクトリをコンテナのworkディレクトリにマウントしています。4. データ解析環境にアクセスする。
ブラウザを開いて
http://localhost:10000/?token=<token>
にアクセスします。<token>
の値はdocker run
した時にコンソールに表示されます。JupyterLabのLauncherが表示されれば環境構築は完了です。jupyter/datascience-notebookとは
ここで実行した
jupyter/datascience-notebook
は、Jupyter Docker Stacksで管理されているDockerイメージの一つです。docker run
することでJupyter NotebookまたはJupyterLabのサーバを実行します。Jupyter Docker Stacksとは
Jupyter Docker Stacksは、Jupyter公式で管理されているDockerイメージです。Jupyterのアプリケーションとその他各種ツールがあらかじめインストールされ、すぐに実行可能な状態になっています。用途ごとに複数のイメージがあり、2019年2月現在では以下のイメージが存在します。
- jupyter/base-notebook
- jupyter/minimal-notebook
- jupyter/r-notebook
- jupyter/scipy-notebook
- jupyter/tensorflow-notebook
- jupyter/datascience-notebook
- jupyter/pyspark-notebook
- jupyter/all-spark-notebook
jupyter/datascience-notebookの内容
jupyter/datascience-notebook
はデータ解析のためにJulia、Python、Rのライブラリを追加したイメージです。主な機能は以下の通りです。
jupyter/scipy-notebook
とjupyter/r-notebook
に含まれる機能全て- Juliaのコンパイラと基本的な環境
- JuliaのコードをJupyter notebookで実行するためのIJulia
- HDF5、Gadfly、RDatasetsパッケージ
最後に
上記の手順で構築した環境で特集のサンプルコードを実際に実行できることを確認しました。環境構築にかかった時間はほぼDockerイメージのダウンロード待ちだけでした。同じ環境を自力で構築するのは結構大変だと思います。Dockerの便利さを改めて認識しました。
参考URL
- 投稿日:2019-02-28T22:44:45+09:00
Docker、仮想化の概要理解〜HelloWorldまでやってみる
対象読者
Dockerがすげえ技術なのはわかるけどそれ以外何もわからない方
VMWareとかVirtualBoxと何が違うかわからない方はじめに
仮想化技術の概要から始まり、Dockerと従来の仮想化技術の違い、DockerでHelloWorldする方法までを解説する記事となります。DockerはインフラやのにHelloWorldてなんやねんってツッコミたい気持ちはわかりますがちゃんとHelloWorldします。
本記事対象外の内容
Dockerのインストール方法
英語だけでなく日本語でも豊富に記事が存在しているかと思いますのでそちらをご参照ください。そもそも仮想化とは?
仮想化技術を用いるとWindows上でLinuxOSを動作させたり、MacOS上でLinuxを動作させたりすることができます。物理環境の差異を隠して表面を変える技術だとか説明されます。開発においてはかなり便利です。
例えば、開発環境の違いで想定通りに動作しなかったり、わけわかんないエラーが出たり、あるいは競合するプログラムがあったりするとかなり面倒です。同じMacOSで開発していてもバージョンが違うために動作しなかったりする事もあります。
仮想化を行うことで、こうした開発環境による差異を無くし、さらにプロジェクト毎に開発環境を分けられるのでプログラムの競合が起こる事も減ります。Dockerはそうした仮想化技術の1種です。
仮想化の種類
仮想化には大きく分けて2種類の仮想化があります。
- ホスト型仮想化
- コンテナ型仮想化
ホスト型がVMWareやVirtualBoxなどの従来の仮想化技術です。
それに対しDockerはコンテナ型と呼ばれます。ホスト型仮想化では仮想化ソフトウェアを用いて仮想的なOSを構築します。構築されたOSの上でアプリケーションを動作させるためOSによる差異をなくすことができます。ただしオーバーヘッドが大きく、加えて起動時にCPUリソース、メモリ、ストレージなどを割り当てるため起動に時間がかかります。それに対してDocker(コンテナ型)ではカーネルをホストOSと共有するためオーバーヘッドが非常に少ないです。実行環境の違いをコンテナエンジン(=docker)が吸収し、様々なソフトウェアが詰まったコンテナを動作させることで実行環境を構築します。コンテナについては後述します。
Dockerの利点
コンテナ型仮想化ではゲストOSを持たないため以下の利点があります。
処理速度が早い
ホスト型仮想化ではゲストOSを構成する際にCPUリソースやメモリ、ストレージの割り当てが行われるが、コンテナ型技術ではゲストOSを構成しないためオーバヘッドが非常に少ない。(=消費するリソースが少ない)
起動が早い
Dockerデーモン(Dockerのアプリのこと)が立ち上がってればよくてゲストOSを構成したりしないから当然早い
可搬性が高い
Dockerエンジンがあれば動く。要するにどこでも動くイメージが軽い
インフラのコード化
色々やらなくていい
便利機能満載
コンテナ型仮想化独自のメリットという訳ではないが色々設定できるようになると高機能
メリットをたくさんあげましたが、1点注意点としてLinux系のCentOSやUbuntuなどのコンテナが存在しますが、あれは完全なOSを構築している訳ではなく、あくまでカーネルはホストOSであるという点に注意するべきです。カーネルを共有させるべきコンテナは動作させる事ができません。
コンテナ、Dockerイメージ
Dockerイメージとはコンテナ実行に必要なファイルをまとめたファイルシステムです。AUFSなどの特殊なファイルシステムが使用されています。イメージ上のデータはレイヤで構成されていて読み取り専用となっています。その上に構成されるコンテナレイヤーが読み書き可能なレイヤーです。Dockerイメージ+コンテナレイヤーでコンテナとなるイメージです。図にすると下のような感じ。
具体例をみてみましょう
CentOSのベースイメージを継承してRubyの実行環境のレイヤーを加えています。因みにベースイメージとは何も継承していない基底イメージのことです。
図4 CentOSベースイメージの継承
作成したRubyの実行環境のイメージをさらに継承してRailsの実行環境も作成できます。
図5 Rubyの実行環境にRailsのレイヤーを加える例
このようにレイヤーを重ね合わせてイメージを作成します。
次は同じイメージを継承する場合です。この場合、CentOSレイヤーを共有することができます。2重でレイヤーを用意しなくていいのでイメージサイズが小さくなります。さらに差分のイメージだけを取得することになるので、通信量も抑えることができます。
Dockerに触れてみる
Dockerのインストールは省略します。わかりやすい記事が豊富にあると思うのでググってみてください。今回はDockerの動作原理などを確認するのが目的です。
1.Dcokerデーモンが起動していることを確認
図7 Dockerデーモンの起動を確認
Docker is runningとなってればOKです。図3で言うところのコンテナエンジンがこれです。
2.ターミナル上でHello Worldしてみる
Dockerで単純なイメージの取得と動作を確認しましょう。ターミナルを開いて以下のコマンドを入力してみてください。run はその後ろに記述したイメージを取得して実行するサブコマンドです。このコマンドではhell-worldというイメージを取得して実行します。
$ docker run hello-world初めて実行したのであれば↓のような結果が返ってくると思います。
Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 1b930d010525: Pull complete Digest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/7行目でHello from Docker!と出てますね。
他の記述はどのように動作しているかを細かく説明してくれています。
何をしたのか
図で表すとこんな感じです。Dockerクライアントが実行しているコマンドという認識です。Dockerデーモンが1で起動を確認したソフトです。
図8 動作概要図
1.コマンドを実行するとDockerクライアントはDockerデーモンに接続し、hello-worldイメージを探します。
2.初めて実行した場合はローカル上にイメージは存在しないので、Docker Hub(次の記事で解説)というDocker社がホスティングしているサーバーにアクセスしイメージを探します。
3.イメージが見つかるとダウンロードしてPC上に保存します。
4.取得したイメージを実行します。イメージがPC上に存在する場合は②と③が省略されるので動作が最初に比べて早いです。
試しにもう一度実行するとターミナル上で以下のような結果が返ってくると思います。
Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/以下の記述がなくなっているのがわかると思います。
Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 1b930d010525: Pull complete Digest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535 Status: Downloaded newer image for hello-world:latestローカル上でイメージが見つからなかったのでプルしましたって記述です。②と③が消えたのがわかったかと。
docker runコマンドを細かくみてみる
docker runコマンドは以下のコマンドをまとめたコマンドです。
docker pull:イメージの取得 docker create:コンテナの作成 docker start:コンテナの起動よく使うコマンドなので少しづつ覚えていきましょう。
今回はここまで。
- 投稿日:2019-02-28T22:39:36+09:00
オフラインMacでDocker containerからHostOSへ接続する
背景
日頃はオンラインで, Docker containerからHostOSへの接続はHostOSのhostnameで解決していた. 久しぶりにオフラインでDocker containerからHostOSへ接続しようとしたら127.0.0.1が返ってきた. Docker containerのloopbackと競合するので困った.
環境
- OS: macOS Mojave Version 10.14.3
- Docker Desktop:
シンプルな解決策
host.docker.internal を使用するとDocker containerからHostOSへ接続できる.
Networking features in Docker Desktop for Mac
I WANT TO CONNECT FROM A CONTAINER TO A SERVICE ON THE HOST
The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal, which resolves to the internal IP address used by the host. This is for development purpose and will not work in a production environment outside of Docker Desktop for Mac.
シンプルでない解決策
loopback interface lo0にaliasを設定し, aliasへ接続する.
$ sudo ifconfig lo0 alias xxx.xxx.xxx.xxx $ sudo ifconfig lo0 -alias xxx.xxx.xxx.xxxオフライン時にHostOSのhostnameを解決したら127.0.0.1が返ってくるのは何故?
オンライン時とオフライン時を比較してみる
HostOSへ接続している.terminal.container.online$ ping HOSTNAME.local PING HOSTNAME.local (xxx.xxx.xxx.xxx): 56 data bytes 64 bytes from xxx.xxx.xxx.xxx: seq=0 ttl=37 time=0.758 ms 64 bytes from xxx.xxx.xxx.xxx: seq=1 ttl=37 time=1.172 ms自Containerへ接続している.terminal.container.offline$ ping HOSTNAME.local PING HOSTNAME.local (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: seq=0 ttl=64 time=0.058 ms 64 bytes from 127.0.0.1: seq=1 ttl=64 time=0.155 msterminal.hostos.online$ ifconfig lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP> inet 127.0.0.1 netmask 0xff000000 inet6 ::1 prefixlen 128 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 nd6 options=201<PERFORMNUD,DAD> en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 ether xx:xx:xx:xx:xx:xx inet6 xxxx::xxxx:xxxx:xxxx:xxxx%en0 prefixlen 64 secured scopeid 0x8 inet xxx.xxx.xxx.xxx netmask 0xfffffff0 broadcast xxx.xxx.xxx.xxx nd6 options=201<PERFORMNUD,DAD> media: autoselect status: activeterminal.hostos.offline$ ifconfig lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP> inet 127.0.0.1 netmask 0xff000000 inet6 ::1 prefixlen 128 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 nd6 options=201<PERFORMNUD,DAD> en0: flags=8823<UP,BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500 ether xx:xx:xx:xx:xx:xx nd6 options=201<PERFORMNUD,DAD> media: autoselect (<unknown type>) status: inactiveterminal.hostos.online$ netstat -rn Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default xxx.xxx.xxx.xxx UGSc 123 0 en0 127 127.0.0.1 UCS 0 0 lo0 127.0.0.1 127.0.0.1 UH 11 59676 lo0 他色々terminal.hostos.offline$ netstat -rn Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire 127 127.0.0.1 UCS 0 0 lo0 127.0.0.1 127.0.0.1 UH 11 59680 lo0 他色々
- オンライン
- IPAddress(xxx.xxx.xxx.xxx)へ接続している
- en0が生きている
- Routing tablesにen0がある
- オフライン
- 127.0.0.1へ接続している
- en0が死んでいる
- Routing tablesにlo0しかない
Multicast DNSを使っていた
そもそもDNSでhostnameを解決しておらず, hostnameコマンドで取得できる名前がHOSTNAME.localだった. .localはMulticast DNSで解決されるのでDNSとはちょっと異なる. ざっくり言うと"ホスト名さえ分かれば通信できるよぁ"ってプロトコル. MacだとBonjourで動いている.
Metricsが分からない
複数ルーティングルールがある場合, どのルーティングルールを適用するか?といった優先度を決めるMetricという値がある. loopback interface lo0とen0のMetricをMacOSで確認しようとしたが見つからない. 敢えていうなら, System Preferences > NetworkのSet Service Order...が該当するがloopback項目がない.
推測してみる
MacOSのルーティングルールのMetricはSystem Preferences > NetworkのSet Service Order..で設定されていて, 暗黙のルールでloopbackは最下位設定になっている. オフライン時はloopback interface lo0のみ有効となる. 併せて, Multicast DNSで解決した場合loopback interface lo0の127.0.0.1となる. 全部, 妄想.
ついでに
docker networkはdefault bridgeとユーザー定義ネットワークでDNS設定が異なるらしい. docker containerからHostOSへの接続を詳しく知りたい方はどうぞ.
所感
terminal.container.offline/srv # ping host.docker.internal PING host.docker.internal (???.???.???.???): 56 data bytes 64 bytes from ???.???.???.???: seq=0 ttl=37 time=0.373 ms 64 bytes from ???.???.???.???: seq=1 ttl=37 time=0.893 mshost.docker.internalだとレスポンスが早いので通信が閉じた感じなのかな? Dockerはまだまだ落ち着かないので, しっかり追わないと駄目ですね. これでネットワーク難民時にも色々遊べる. ちゃんちゃん.
参考文献
- 投稿日:2019-02-28T22:13:27+09:00
Go 1.12 の開発環境と本番環境の Dockerfile を考える
はじめに
Go 1.12 がリリースされましたね!
TLS 1.3 の対応や Go Modules の改良がされたようです。
Go 1.12 is released - The Go Blog今回は Go Modules が含まれている Go 1.12 を使用して、開発環境と本番環境の Dockerfile の作成を考えてみます。
開発環境は docker-compose、本番環境は Kubernetes などのオーケストレーションツールにデプロイすることを想定した Dockerfile の作成を考えます。アプリケーションは、Go Modules を利用してライブラリ管理し、外部に HTTPS 通信するアプリケーションを想定して Dockerfile を作成しています。
Listen ポートは 8080 ポートです。環境
- macOS High Sierra Version 10.13.6
- Docker for Mac 2.0.0.3 (Engine: 18.09.2)
ディレクトリ構成
以下のようなルートディレクトリに main.go が存在するようなアプリケーションを想定しています。
├── Dockerfile // 開発環境の Dockerfile ├── Dockerfile.prod // 本番環境の Dockerfile ├── docker-compose.yml // 開発環境の docker-compose ├── go.mod ├── go.sum └── main.go開発環境
開発環境はソースコードが随時変更されるため、
fresh
というライブラリを用います。
ソースコード自体は、docker-compose で指定するルートを docker volume に割り当て、ホットリロードを実現します。Dockerfile
開発環境の Dockerfile の全体は以下のとおりです。
DockerfileFROM golang:1.12.0-alpine3.9 WORKDIR /go/src/app ENV GO111MODULE=on RUN apk add --no-cache \ alpine-sdk \ git \ && go get github.com/pilu/fresh EXPOSE 8080 CMD ["fresh"]Dockerfile の詳細
開発環境の Dockerfile の詳細を追ってみます。
FROM golang:1.12.0-alpine3.9イメージは、執筆時点(2019/02)の最新の Alpine Linux の Go イメージを指定しています。
WORKDIR /go/src/app
WORKDIR
でアプリケーションを実行するディレクトリを指定しています。ENV GO111MODULE=onGo 1.12 では、Go Modules を使用するために必要な環境変数
GO111MODULE
をon
にしています。RUN apk add --no-cache \ alpine-sdk \ git \ && go get github.com/pilu/freshパッケージとして一通りビルドに必要なものが入っている
alpine-sdk
と Go Modules でライブラリ取得時に内部的にgit
を利用しているのでgit
をインストールしています。
また、Go 開発のホットリロードで利用するfresh
をインストールしています。EXPOSE 80808080 ポートで Listen するアプリケーションなので、
EXPOSE
命令で 8080 ポートを明示しています。CMD ["fresh"]最後に
fresh
で起動することで、ホットリロードで起動する Dockerfile の完成です。docker-compose
開発環境の docker-compose ファイルは以下のとおりです。
docker-compose.ymlversion: '3' services: app: build: . volumes: - ./:/go/src/app ports: - "8080:8080"docker-compose の詳細
開発環境の docker-compose の詳細を追ってみます。
build: .
build
で ビルドする Dockerfile のディレクトリを指定しています。volumes: - ./:/go/src/app
volumes
で Dockerfile でも指定したWORKDIR
のディレクトリに対してマウントしています。こうすることでコンテナ内から開発マシンのディレクトリが見えるようになり、fresh
のビルド対象になります。ports: - "8080:8080"
ports
は、8080 ポートで Listen するアプリケーションなので、開発マシンとコンテナのポートを割り当てています。開発環境の実行
以下の docker-compose コマンドで起動し、
localhost:8080
にアクセスすることで開発が始められます。$ docker-compose up -d本番環境
本番環境は可能な限り小さいイメージを作るために、マルチステージビルドを用います。
Dockerfile
本番環境の Dockerfile の全体は以下のとおりです。
Dockerfile.prodFROM golang:1.12.0 as builder WORKDIR /go/src/app ENV GO111MODULE=on RUN groupadd -g 10001 myapp \ && useradd -u 10001 -g myapp myapp COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/app FROM scratch COPY --from=builder /go/bin/app /go/bin/app COPY --from=builder /etc/group /etc/group COPY --from=builder /etc/passwd /etc/passwd COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt EXPOSE 8080 USER myapp ENTRYPOINT ["/go/bin/app"]Dockerfile の詳細
本番環境の Dockerfile の詳細を追ってみます。
FROM golang:1.12.0 as builderイメージは Alpine Linux ではなくデフォルトのイメージに変更し、マルチステージビルドを用いるために
as builder
というステージ名を指定しています。
デフォルトのイメージに変更したのは、Go Modules のインストールに必要なgit
や Go ライブラリのインストールや Go のビルドに必要なパッケージが含まれているためです。
マルチステージビルドについては、ステージ名に任意の名前が付けられます。
こうすることで、次のステージでビルドした成果物をコピーすることができます。RUN groupadd -g 10001 myapp \ && useradd -u 10001 -g myapp myappここでは、ユーザーグループとユーザーを作成しています。
これは、次のステージで利用するアプリケーションの実行ユーザーを作成するために実行しています。
また、次のステージで利用するscratch
イメージは shell が実行できないため、ビルドステージでユーザーを作成しています。COPY go.mod go.sum ./ RUN go mod download COPY . .開発環境では volume にマウントしていましたが、本番環境ではアプリケーションをそのままコンテナ内にコピーしています。
そして、COPY
命令で全てのファイルをコピーせず、事前にgo.mod
とgo.sum
ファイルをコピーしています。
これは、コピー後にgo mod download
を実行してライブラリをインストールすることで、次回以降ライブラリの追加、go.mod
とgo.sum
に変更がなくソースコードの変更のみであればソースコード全体をコピーするCOPY . .
の行から実行され、それより前のステップはキャッシュが活用されスキップされます。
こうすることでキャッシュが有効活用されるので、インストールのステップをスキップし、ビルド速度が向上します。RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/appクロスコンパイル用の環境変数を指定し、
-ldflags="-w -s"
でバイナリを削減しています。FROM scratch前述のとおり
scratch
イメージは、shell も入っていない最小のイメージです。
小さなイメージを作るには良いですが、attach も出来ないので取り回しが悪い点は否めません。
状況によって、Alpine Linux のイメージを使うと良いと思います。COPY --from=builder /go/bin/app /go/bin/app前のステージでビルドしたアプリケーションを次のステージにコピーしています。
--from=[NAME]
をコピーするファイルの前に宣言することでコピー元のステージが指定できます。COPY --from=builder /etc/group /etc/group COPY --from=builder /etc/passwd /etc/passwdここでは、ビルドステージからユーザーグループとユーザーのファイルをコピーしています。
このファイルをコピーすることで、ユーザーグループとユーザーを追加したことになるので、実行ユーザーを変更することが可能になります。COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crtここでは、HTTPS 通信をするために証明書をコピーしています。
HTTPS 通信をしないのであれば不要です。USER myapp作成したユーザーを
myapp
ユーザーに変更しています。
デフォルトでは root ユーザーで実行されるため、非 root ユーザーで実行するためにユーザーを変更しています。ENTRYPOINT ["/go/bin/app"]最後に
ENTRYPOINT
でアプリケーションを実行しています。
ENTRYPOINT
でコマンドを指定することで、引数を用いるアプリケーションであれば実行時に引数がそのまま指定できます。本番環境の実行
本来であれば CI でビルドし、CD でコンテナオーケストレーション環境にデプロイしますが、確認のために開発マシンで起動します。
Dockerfile をビルドします。
$ docker build -t myapp -f Dockerfile.prod .8080 ポートでビルドしたコンテナを起動します。
$ docker run --name myapp -p 8080:8080 -it -d myappdocker top コマンドで実行ユーザーを確認してみます。
$ docker top myapp PID USER TIME COMMAND 13606 10001 0:00 /go/bin/app
USER
が10001
で実行されていることが分かります。番外編
本番環境の例では、ビルドステージにデフォルトのイメージを使用して作成しました。
ただし、デフォルトのイメージを採用することによるデメリットも存在します。
以下に示すのは、デフォルトの Go と Alpine Linux の Docker イメージを比較したものです。golang 1.12.0-alpine3.9 d4953956cf1e 17 hours ago 347MB golang 1.12.0 c4f8e4c91496 17 hours ago 772MB見てわかるとおり二つのイメージには、400MB 程度のイメージサイズの差があります。
これはつまり、Docker イメージを pull するときのダウンロード速度に影響します。
同じベースイメージを使っていれば再利用されますが、Go のバージョンアップをするときにベースイメージを変更する必要があるため、その時点では全体のビルド速度が低下します。ビルドステージに Alpine Linux のイメージを使用した Dockerfile の全体は以下のとおりです。
Dockerfile.prodFROM golang:1.12.0-alpine3.9 as builder WORKDIR /go/src/app ENV GO111MODULE=on RUN addgroup -g 10001 -S myapp \ && adduser -u 10001 -G myapp -S myapp RUN apk add --no-cache \ alpine-sdk \ git COPY . . RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/app FROM scratch COPY --from=builder /go/bin/app /go/bin/app COPY --from=builder /etc/group /etc/group COPY --from=builder /etc/passwd /etc/passwd COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt EXPOSE 8080 USER myapp ENTRYPOINT ["/go/bin/app"]変更点としては、イメージをデフォルトから Alpine Linux のイメージに変更しています。
FROM golang:1.12.0-alpine3.9 as builderまた、Debian 系と Alpine Linux とでディストリビューションが異なるため、ユーザーグループとユーザー追加のコマンドが異なります。
RUN addgroup -g 10001 -S myapp \ && adduser -u 10001 -G myapp -S myappそして開発環境同様、
alpine-sdk
とgit
をインストールし、ファイルを全てコピーするように変更しています。RUN apk add --no-cache \ alpine-sdk \ git COPY . .Alpine Linux を採用するメリットは、イメージサイズの小ささによるダウンロードの速さです。
毎度イメージのダウンロードからパッケージのインストールまで行うのであれば、デフォルトのイメージに比べイメージが小さい分速く終わります。しかしながら番外編の Dockerfile にもデメリットがあり、本番環境の例で採用しなかったのは以下の理由からです。
Go Modules のインストールには、git
に依存しているためgit
のインストールが必要です。
また、Go ライブラリのインストールや Go のビルドにはgcc
などのパッケージが必要な場合があるため、alpine-sdk
をインストールしています。
Alpine Linux のイメージにはそれらがデフォルトでインストールされていないため、事前にインストールする必要があります。
しかしそれらをインストールしてしまうと Docker のキャッシュがリセットされ、ソースコードを変更する度にパッケージのインストールが再度実行されてしまいます。
本番環境の例で紹介したデフォルトのイメージであればgit
や必要なパッケージがインストールされているので、Docker のキャッシュを有効活用してソースコードのコピーより前のステップをスキップすることができます。
したがって、毎度のソースコードの変更が主なビルドを考えると Docker のキャッシュが有効なデフォルトのイメージが良いと思います。Go のライブラリを使用しないなど、パッケージをインストールしないのであれば、Alpine Linux を選択するメリットがあると思います。
さいごに
ここまで、Go 1.12 の開発環境と本番環境の Dockerfile の最適化を考えました。
次には Go 1.13 のリリースが控えていますが、Go Modules 自体は Go 1.13 からデフォルトで有効になるとのことなので、GO111MODULE
の環境変数が不要になる程度で概ね使えるのではないでしょうか。
また、Docker 18.09 で正式に追加されたBuildKit
を試していないので、BuildKit
を使うことでより最適化できるかもしれません。参考
Go v1.11 + Docker + fresh でホットリロード開発環境を作って愉快なGo言語生活
Create the smallest and secured golang docker image based on scratch
Non-privileged containers based on the scratch image
Use Multi-Stage Builds to Inject CA Certs
- 投稿日:2019-02-28T21:52:51+09:00
Docker で NextCloud & OnlyOffice 環境を構築した時の備忘録
はじめに
Docker で NextCloud & OnlyOffice 環境を構築した時の備忘録。
基本的には以下のサイトの手順に従う。
How to Easily Integrate OnlyOffice and NextCloud Using Dockerが、OSが違ったり、手順通りでうまくいかなかったところがあるので。
【環境、使用ソフトなど】
・さくらVPS
・CentOS7
・Docker
・NextCloud
・OnlyOffice
・Let's Encryptドメインの取得、DNS設定
httpsでのアクセスが基本となるようなので、あらかじめドメインを取得してさくらVPSへのDNS設定をしておく。
今回はとりあえずお試しということで無料の
freenom
を使用。まずはユーザ登録、ドメイン取得。
このあたりは参考になるページがいくつもあるので、割愛。
こんな感じでドメインとさくらVPSのIPアドレスを紐付けるAレコードを登録する。
さくらVPSの設定
さくらVPSで、CentOS7をインストールし、基本設定を行う。
このあたりも参考サイトがあるので、実際に実行したコマンドだけ雑に列挙。・CentOS7を選択してOSインストール
スタートアップスクリプトは選択しない。・インストール済みのパッケージをアップデート
# yum update・日本語化、結果確認
# localectl set-locale LANG=ja_JP.UTF-8 # localectl status System Locale: LANG=ja_JP.UTF-8 VC Keymap: jp106 X11 Layout: jp・ユーザ追加
# useradd ユーザ名・パスワード設定
# passwd ユーザ名 →パスワードを設定・権限の設定
# usermod -G wheel ユーザ名・追加したユーザでsudoできるように設定
# visudo## Allows people in group wheel to run all commands #%wheel ALL=(ALL) ALL ←この行がコメントアウトされていたら、コメントアウトを解除。# vim /etc/pam.d/su/etc/pam.d/su# Uncomment the following line to require a user to be in the "wheel" group. #auth required pam_wheel.so use_uid ←この行がコメントアウトされていたら、コメントアウトを解除。 auth substack system-auth参考:基本設定 | 初心者でもわかる!さくらVPS | Sakura VPS 設定マニュアル
必要があれば、rootのパスワードの変更やログイン禁止なども適当に。
で、作業ユーザでログインし直す。ポート開放
http,httpsのポートを開放する。
$ sudo firewall-cmd --zone=public --add-service=http --permanent $ sudo firewall-cmd --zone=public --add-service=https --permanent $ sudo firewall-cmd --reload $ sudo firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client ssh http https ←http,httpsが追加されている。 ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:Dockerのインストール
すでにインストールされていたら削除
$ sudo yum remove docker docker-common docker-selinux docker-engine最新バージョンをインストール
$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2 $ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo $ sudo yum makecache fast $ sudo yum install docker-ce起動
$ sudo systemctl start dockersudoグループに追加(sudoを付けなくてもdockerコマンドが使用できるように)
$ sudo groupadd docker $ sudo usermod -aG docker ユーザ名※ 「sudo groupadd docker」はすでに存在するため不要のはずだが、念のため。
自動起動の設定
$ sudo systemctl enable dockerOS再起動(念のため)
$ rebootDocker Composeのインストール
インストール
$ sudo curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-` > uname -m` -o /usr/local/bin/docker-compose →パスワード入力 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 617 0 617 0 0 752 0 --:--:-- --:--:-- --:--:-- 752 100 11.2M 100 11.2M 0 0 1765k 0 0:00:06 0:00:06 --:--:-- 2677k※ バージョンは、
https://github.com/docker/compose/releases
で確認できる。実行権限付与
$ sudo chmod +x /usr/local/bin/docker-compose確認
$ docker -v Docker version 18.09.2, build 6247962 $ docker-compose --version docker-compose version 1.23.2, build 1110ad01参考:How to Easily Integrate OnlyOffice and NextCloud Using Docker
docker-onlyoffice-owncloudの設定
gitからファイル取得
git clone --recursive https://github.com/ONLYOFFICE/docker-onlyoffice-owncloud cd docker-onlyoffice-owncloud git submodule update --remotedocker-compose.ymlの設定
vi docker-compose.yml5行目を「image: nextcloud:fpm」に変更する。
docker-compose.ymlersion: '3' services: app: container_name: app-server image: nextcloud:fpm ←変更 stdin_open: true tty: truenginxブロックに「- /etc/letsencrypt:/etc/letsencrypt」を追記する。
docker-compose.ymlnginx: container_name: nginx-server image: nginx stdin_open: true tty: true restart: always ports: - 80:80 - 443:443 networks: - onlyoffice volumes: - ./nginx.conf:/etc/nginx/nginx.conf - app_data:/var/www/html - /etc/letsencrypt:/etc/letsencrypt ←追記 networks: onlyoffice: driver: 'bridge'nginx.confの設定
vi nginx.confサーバブロックにサーバのドメインを追加する。
nginx.confserver { listen 80; ↓↓↓↓↓↓↓↓↓追記 server_name ドメイン名; ↑↑↑↑↑↑↑↑↑追記 # Add headers to serve security related headers add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;"; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header X-Robots-Tag none; add_header X-Download-Options noopen; add_header X-Permitted-Cross-Domain-Policies none;dockerコンテナ起動
$ docker-compose up -d確認
$ docker network ls NETWORK ID NAME DRIVER SCOPE 6ea1f4ff6067 bridge bridge local 33d05649cf53 dockeronlyofficeowncloud_onlyoffice bridge local 56fe104ece72 host host local d10e8d381e95 none null local $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b645decc529b onlyoffice/documentserver:latest "/bin/sh -c /app/onl…" About a minute ago Up About a minute 80/tcp, 443/tcp onlyoffice-document-server 5d0ed88e01c1 nginx "nginx -g 'daemon of…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-server 48192a961cbc nextcloud:fpm "/entrypoint.sh php-…" About a minute ago Up About a minute 80/tcp, 9000/tcp app-serverhttp://ドメイン名.com
でサイトにアクセスできることを確認する。
とりあえずここまででNextCloudの構築は成功。※ Chromeで一度httpsで接続してしまうと、再構築後もhttpsにリダイレクトされてしまって接続できない現象が発生。その場合、以下を参考にHSTSを削除する。
Chromeでhttpからhttpsへ強制リダイレクトされる場合の対処法
Let's Encryptの設定
まずはインストール
$ sudo yum install epel-release $ sudo yum install certbotnginx.confにLet's Encryptアクセス用の定義を追加
vi nginx.conf末尾にlocationを追加する。
nginx.conf# Optional: Don't log access to other assets location ~* \.(?:jpg|jpeg|gif|bmp|ico|png|swf)$ { access_log off; } ↓↓↓↓↓↓↓↓↓追記 location ~ /.well-known/acme-challenge { root /var/www/html/; allow all; } location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; root /var/www/html/; } ↑↑↑↑↑↑↑↑↑追記 } }NGINX再起動
$ docker restart nginx-server※ 参考サイトでは
location ~ /.well-known/acme-challenge {
の記載だったが、証明書の発行でエラーになった。
参考サイトのコメントに従って、location ^~ /.well-known/acme-challenge/ {
も追加する。証明書発行
$ sudo certbot certonly --webroot --agree-tos --email メールアドレス -d ドメイン名 -w /var/lib/docker/volumes/docker-onlyoffice-owncloud_app_data/_dataこんなメッセージが出て、
/etc/letsencrypt/live/ドメイン名/fullchain.pem
/etc/letsencrypt/live/ドメイン名/privkey.pem
が生成されたら成功。IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/ドメイン名/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/ドメイン名/privkey.pem Your cert will expire on 2019-05-25. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-lenginx.confのサーバブロックにSSL証明書の設定を追加する。
vi nginx.confnginx.confserver { listen 80; server_name ドメイン名; ↓↓↓↓↓↓↓↓↓追記 listen 443 ssl http2; # if ($scheme != "https") { # return 301 https://$host$request_uri; # } ssl_certificate /etc/letsencrypt/live/ドメイン名/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/ドメイン名/privkey.pem; ssl_session_cache shared:le_nginx_SSL:1m; ssl_session_timeout 1440m; ssl_protocols TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; ↑↑↑↑↑↑↑↑↑追記 # Add headers to serve security related headers add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;"; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header X-Robots-Tag none; add_header X-Download-Options noopen; add_header X-Permitted-Cross-Domain-Policies none;※ 構築後にスプレッドシートを開こうとすると、「文書を保存できませんでした。」のエラーになったので、参考サイトのコメントに従って、
if ($scheme != "https") { ・・・
からの3行はコメントアウトする。NGINX再起動
$ docker restart nginx-server今度は「https://ドメイン名」でアクセスできること、証明書が有効になっていることを確認する。
MariaDBの設定
インストール
$ docker run --restart=always --net docker-onlyoffice-owncloud_onlyoffice --name mariadb-server -e MYSQL_ROOT_PASSWORD=パスワード -d mariadb --log-bin --binlog-format=MIXED※ 微妙にオプションが違ってた。Dockerのバージョンのせい?
--net dockeronlyofficeowncloud_onlyoffice
→--net docker-onlyoffice-owncloud_onlyoffice
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a8669abf86cb mariadb "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 3306/tcp mariadb-server bb915afe1f28 onlyoffice/documentserver:latest "/bin/sh -c /app/onl…" 26 hours ago Up 26 hours 80/tcp, 443/tcp onlyoffice-document-server 9446de803483 nextcloud:fpm "/entrypoint.sh php-…" 26 hours ago Up 26 hours 80/tcp, 9000/tcp app-server f311556e7c31 nginx "nginx -g 'daemon of…" 26 hours ago Up 20 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-serverMariaDBのdockerにログイン
$ docker exec -it mariadb-server bashMariaDBでデータベース作成など
mysql -u root -p →rootのパスワードを入力。 create database nextcloud; create user nextclouduser@172.18.0.3 identified by 'パスワード'; grant all privileges on nextcloud.* to nextclouduser@172.18.0.3 identified by 'パスワード'; flush privileges; exit; exit※ IPアドレスは「172.18.0.3」のはずだが、念のため確認する。
docker inspect app-server | grep IPAddress
NextCloudにログイン
以下の設定を入力し、「セットアップを完了します」を選択する。
(管理者アカウント、パスワードは適当に設定。)
設定値 データフォルダー /var/www/html/data ※変更なし データベース MySQL/MariaDB データベースのユーザー名 nextclouduser データベースのパスワード 上で設定したパスワード データベース名 nextcloud localhost mariadb-server NextCloudにログインできることを確認する。
あなたの全データの安全な家・・・。OnlyOfficeとの連携
以下のコマンドを発行
$ sudo bash set_configuration.sh以下のエラーになった。
App "ONLYOFFICE" cannot be installed because it is not compatible with this version of the server.onlyofficeを再取得して置き換える。
$ cd .. $ sudo git clone --depth=1 https://github.com/ONLYOFFICE/onlyoffice-nextcloud.git onlyoffice $ sudo mv onlyoffice/ /var/lib/docker/volumes/docker-onlyoffice-owncloud_app_data/_data/apps/「ファイルが存在します」のエラーとなった。
cpならどうか。$ sudo cp -rf onlyoffice/ /var/lib/docker/volumes/docker-onlyoffice-owncloud_app_data/_data/apps/ cp: ディレクトリではない `/var/lib/docker/volumes/docker-onlyoffice-owncloud_app_data/_data/apps/onlyoffice/.git' をディレクトリ `onlyoffice/.git' で上書きすることはできませんどうやら「.git」のファイルが邪魔しているらしい。
削除して再度cp。$ sudo rm /var/lib/docker/volumes/docker-onlyoffice-owncloud_app_data/_data/apps/onlyoffice/.git $ sudo cp -rf onlyoffice/ /var/lib/docker/volumes/docker-onlyoffice-owncloud_app_data/_data/apps/今度は成功したらしい。
で、再度コマンド発行。$ cd docker-onlyoffice-owncloud $ sudo bash set_configuration.sh今度は成功。
NextCloudのページをリロードすると、SpreedSheetなどが作成可能になっている。
- 投稿日:2019-02-28T21:42:24+09:00
[秋葉原] ゼロから始めるKubernetes入門会 #1 (初心者大歓迎!) 後半資料
[秋葉原] ゼロから始めるKubernetes入門会 #1 (初心者大歓迎!)
docker本番で使えるんじゃね?という話
既存の仮想化技術 Docker 分類 ホストOS型の仮想化 コンテナ型仮想化技術
(OS-level virtualization)オーバヘッド 大きい。
H/WをS/Wエミュレート小さい。
ホストのH/W使う環境構築 大変。
手順書通りに
パッケージマネージャを操作簡便。
Dockerfile書いて
docker buildコマンド叩くだけポータビリティ 低い 高い。
ローカルのを本番へ、
本番のをローカルへ用途 ローカル検証 本番にも使える
コンテナで本番アプリケーションを作ろう
- アプリケーションは様々なプロセスから成る
- ベストプラクティス:
コンテナは関心事ごとにひとつ- 1つのコンテナに全部詰め込まない
- アクセスめっちゃ増えた!
- DBは余裕だけどPHPが限界!
=> Nginxとphp-fpm増やす(スケールアウト)
コンテナを複数動かすと
- いろいろ考えること出てくる
- どの順番でコンテナ起動する
- 何番ポートで通信する
docker container run
直接叩くのはもうむり
Docker Compose
- 複数コンテナをいい感じに動かす
- 「いい感じに」...ymlファイルで定義できる
限界
- 唯一一台のノードが壊れたら死ぬ(SPOF)
- 壊れないまでも、性能面で困ったとき
ハードウェアをスケールアウトできない
コンテナオーケストレーション
- 複数ノード上で複数コンテナをいい感じに動かす
- Docker Swarm
- Dockerの名を冠するが、イマイチ流行らなかった
- Kubernetes
- デファクトスタンダード
Kubernetesを使うモチベーション
- 何が嬉しいの?
- 1.ベロシティ(Velocity)
- 2.スケールすること
- 3.インフラの抽象化
- 4.効率性
1.ベロシティ(Velocity) = 速さ
- ユーザの希望
- サービスの機能開発・デプロイが速い(高頻度)
- 信頼性が高い
- 高SLA
- デプロイのたびにメンテしてほしくない
- 一見、相反する無理難題
- これらを両立するのがコンテナとKubernetes
- 1.1 Immutable Infrastracture (不変なインフラ)
- 1.2 宣言的設定
- 1.3 自己回復するシステム
1.1 Immutable Infrastracture (不変なインフラ)
- 古い環境を壊さず、毎回新しく作る
- ある状態ある状態でバージョン管理する
- 万が一何かあればすぐロールバックできる(高信頼性)
1.2 宣言的設定
- 対義語: 命令的
- Aを起動します
- Bを起動します
- Cを起動します
- 戻し方は知りません
- 宣言的
- レプリカ数が1 です
- レプリカ数が2 です
- レプリカ数が3 です
- Immutable Infrastracture + 宣言的設定 = ロールバックしやすい!
1.3 自己回復するシステム
- 初期化してハイおしまい、ではない
- まずい状態になったら回復する
- コンテナが1つ死んで2つになった
=> 1つ新しく生成して3つにする- 誰かがいたずらしてコンテナを4つにした
=> 1つ停止して3つにする- 宣言的設定ならでは
- 「こうあってほしい」という状態をダイレクトに表現
2. スケールすること
- 2.1 サービスのスケール
- 2.2 開発チームのスケール
2.1 サービスのスケール
- めっちゃアクセス集中したら
- ノード(マシン)増やす
- コンテナ増やす
2.2 開発チームのスケール
- 人が増えると
- コミュニケーションコストがやばい
- 意思決定・目的意識の共有が大変
- 例)
n人
のチームで2人組
のコミュニケーションは
nC2 = n(n-1)/2 = O(n^2)件
- 2倍の規模のシステム作りたい
- 2倍の人材を投入しました
- コミュニケーションコストは4倍になりました
- サービスを独立性の高い形で小分けにする(microservice pattern)
- 他サービスとの接続部が明確
- それ以外の部分は小さなサービスに集中できる
- 人材も小分けにできる
- コミュニケーションコスト低くてすむ
3. インフラの抽象化
- パブリッククラウドを使ってサービス構築する場合
- クラウド事業者によって設定の方法とか全然違う
- 各種インフラをKubernetesのリソースとして抽象化
- オレンジとか青とか消えた
4. 効率性
- いい感じにコンテナ配置してくれる
- 物理マシン数節約できる
- 開発のコスト下げられる
Kubernetesすごい!使いたい!
- 頑張ってインストールしてください
Kubernetesのdaemon入れる
- Windows
- Docker for Desktopについてくる
- 要 Windows10 PRO
- チェックボックス入れればすぐ使える
- macOS
- やはりチェックボックス入れればすぐ使える
- linux
- Minikubeを使ってます
- 入れるのそこそこめんどくさい。がんばれ
Kubernetesのclient入れる
- Windows
- kubectl.exe 保存してPATHに追加する
- macOS
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.10.4/bin/darwin/amd64/kubectl \ && chmod +x kubectl \ && mv kubectl /usr/local/bin
- Linux
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.10.4/bin/linux/amd64/kubectl \ && chmod +x kubectl \ && mv kubectl /usr/local/bin
今日つくるもの
Kubernetesの世界観
- ぜんぶ「リソース」
- コンテナ動かすホスト(マシン): Node
- Nodeの集合体: Cluster
- Cluster上で動かす、コンテナの集合体: Pod
- Podの集合体: ReplicaSet
- ReplicaSetを外部公開する人: NodePort Service
Nodeリソース
- 皆さんの目の前にある箱です
- 正確には、そこで動いているコンテナホスト(dockerd)
Clusterリソース
- 今回は単ノード
Podリソース
- コンテナの集合体
- 1コでもPod
- 密結合なほうが都合の良い組
- MySQLのMASTER/SLAVES
- Webサーバーと、前段のNginx
はじめてのPod
- Nginx
- 受け取ったHTTPリクエストをWebサーバーに横流しする
- Webサーバー(Go言語)
- HTTPリクエストを受け取り、200 Statusで"Hello Docker!"を返す
Podの設定ファイル(マニフェストファイル)
- simple-pod.yml
apiVersion: v1 kind: Pod metadata: name: simple-echo spec: containers: - name: nginx image: gihyodocker/nginx-proxy:latest env: - name: BACKEND_HOST value: localhost:8080 ports: - containerPort: 80 - name: echo image: gihyodocker/echo:latest ports: - containerPort: 8080
生成
kubectl apply -f simple-pod.yml
- 確認
kubectl get pod
- コンテナ2個生えた!
NAME READY STATUS RESTARTS AGE simple-echo 2/2 Running 0 6m43s
コンテナ内訳確認
docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 036e14655f14 gihyodocker/echo "go run /echo/main.go" 6 minutes ago Up 6 minutes k8s_echo_simple-echo_default_d299c95c-3b52-11e9-a4d3-28d244ffadef_0 4523acea988c gihyodocker/nginx-proxy "render /etc/nginx/c…" 6 minutes ago Up 6 minutes k8s_nginx_simple-echo_default_d299c95c-3b52-11e9-a4d3-28d244ffadef_0 ...
後始末
kubectl delete -f simple-pod.yml
はじめてのReplicaSet
- ReplicaSet: 同種のPod複数
ReplicaSetのマニフェストファイル
- simple-replicaset.yml
apiVersion: apps/v1 kind: ReplicaSet metadata: name: echo labels: app: echo spec: replicas: 3 selector: matchLabels: app: echo template: metadata: labels: app: echo spec: containers: - name: nginx image: gihyodocker/nginx-proxy:latest env: - name: BACKEND_HOST value: localhost:8080 ports: - containerPort: 80 - name: echo image: gihyodocker/echo:latest ports: - containerPort: 8080
生成
kubectl apply -f simple-replicaset.yml
- 確認
kubectl get pod
- Pod3個生えた!
NAME READY STATUS RESTARTS AGE echo-gnw9n 2/2 Running 0 28m echo-p5s58 2/2 Running 0 28m echo-vctzq 2/2 Running 0 28m
Service
- ReplicaSetは複数のPodからなる
- どれと通信する?
- 意識しなくていい
- サービスディスカバリ
NodePort Service
- クラスタ外(ホスト)からアクセスできる
マニフェストファイル
- simple-nodeport-service.yml
apiVersion: v1 kind: Service metadata: name: echo spec: type: NodePort selector: app: echo ports: - name: http port: 80
生成
kubectl apply -f simple-nodeport-service.yml
- 確認
kubectl get service
- なんか生えた!
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE echo NodePort 10.106.19.140 <none> 80:31875/TCP 40s
kubernetesクラスタ外への公開
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE echo NodePort 10.106.19.140 <none> 80:31875/TCP 40s
- これ
80:31875/TCP
- クラスタ外(ホスト)の
31875
番ポートでアクセスできるよ、ってこと
疎通確認
- ブラウザで http://localhost:31875 開く
Hello Docker!!
- めでたし
後始末
kubectl delete -f simple-nodeport-service.yml kubectl delete -f simple-replicaset.yml
資料
書籍
- Docker/Kubernetes 実践コンテナ開発入門 (技術評論社)
- 入門 Kubernetes (O'Reilly)
- The Mythical Man Month (Addison Wesley)
絵描いたやつ
- 投稿日:2019-02-28T19:04:13+09:00
Rails で Web API 開発(Part. 2 Docker 関連)
はじめに
本記事は、自身が今までの Ruby on Rails で開発してきた知識 / 知見の総まとめをおこなったものです。
「ここは、もっとこうしたほうがいいよ!こういうものがあるよ!」というようなことがあれば、随時おしらせください!
最終的なプロダクトは、 Rails API Sample に置いておきます。各記事
- Rails で Web API 開発(Part. 1 概要)
- Rails で Web API 開発(Part. 2 Docker 関連)
- Rails で Web API 開発(Part. 3 DB 関連)
- Rails で Web API 開発(Part. 4 CORS 関連)
- Rails で Web API 開発(Part. 5 R(CRUD) の実装)
記事の構成
前回の記事
前回は、Mac 上でとりあえず
$ rails server
が動くところまでやりました。今回の記事
今回は、Docker Container 上で
$ rails server
が動くようにします。次回の記事
次回は、しっかりと DB 部分の実装をおこなっていきます。
各種 Docker ファイルの作成
docker-compose.yaml の作成
以下のような docker-compose.yaml を作成します。
version: '3' services: db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql ports: - "40050:3306" restart: always # 環境変数は、Docker 上から流すことにします。 environment: TZ: "Asia/Tokyo" MYSQL_ROOT_PASSWORD: rails_api_sample MYSQL_DATABASE: rails_api_sample MYSQL_USER: rails_api_sample MYSQL_PASSWORD: rails_api_sample app: build: . volumes: - .:/rails_api_sample depends_on: - db ports: - "40000:3000" tty: true stdin_open: true # 環境変数は、Docker 上から流すことにします。 environment: TZ: "Asia/Tokyo" MYSQL_HOST: db MYSQL_DB: rails_api_sample MYSQL_PORT: 3306 MYSQL_USER: rails_api_sample MYSQL_PASSWORD: rails_api_sample volumes: db_data: {}Dockerfile の作成
以下のような Dockerfile を作成します。
FROM ruby:2.6.1 RUN mkdir -p /rails_api_sample WORKDIR /rails_api_sample RUN apt-get update -qq && \ apt-get install -y build-essential mysql-client nodejs tzdata COPY Gemfile* /rails_api_sample/ RUN mkdir -p /rails_api_sample/bin COPY bin/* /rails_api_sample/bin/ RUN ./bin/bundle install --path vendor/bundle COPY . /rails_api_sample # Add a script to be executed every time the container starts. COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 CMD ["./bin/bundle", "exec", "rails", "server", "-p", "3000", "-b", "0.0.0.0", "-e", "development"]Docker 上で rails server
docker-compose up
以下のコマンドを実行します。
$ docker-compose build
次に、以下のコマンドを実行します。
$ docker-compose run --rm app ./bin/bundle install --path vendor/bundle
最後に、以下のコマンドを実行します。
$ docker-compose up
以下のようになったら、とりあえず完了です!( curl コマンド 等で確認してもおそらく DB 周りの設定ができていないのでちゃんとはかえってこないです…。)
各種コマンド
覚えておいたほうがよいコマンドに関して少しだけ記述しておきます。
$ docker-compose up
: docker-compose を起動します。
$ docker-compose down
: docker-compose を停止します。
$ docker-compose run --rm ${SERVICE_NAME} ${COMMAND}
: ${SERVICE_NAME} 内で、指定のコマンドを実行します。 ex)$ docker-compose run --rm app bash
$ docker attach ${CONTAINER_NAME}
: ${CONTAINER_NAME} 内に、入れます。次の例では、binding.pry
等を実行する際によく使います。 ex)$ docker attach rails_api_sample_app
おわりに
まだまだ DB 関連が整っていないです…。次回は、Rails で Web API 開発(Part. 3 DB 関連)を行います。
- 投稿日:2019-02-28T19:03:46+09:00
Rails で Web API 開発(Part. 1 概要)
はじめに
現在、執筆中です。
本記事は、自身が今までの Ruby on Rails で開発してきた知識 / 知見の総まとめをおこなったものです。
「ここは、もっとこうしたほうがいいよ!こういうものがあるよ!」というようなことがあれば、随時おしらせください!
最終的なプロダクトは、 Rails API Sample に置いておきます。対象
- Mac での開発者
- ある程度 Rails / Docker の知識があるとよいかな…。と
各記事
- Rails で Web API 開発(Part. 1 概要)
- Rails で Web API 開発(Part. 2 Docker 関連)
- Rails で Web API 開発(Part. 3 DB 関連)
- Rails で Web API 開発(Part. 4 CORS 関連)
- Rails で Web API 開発(Part. 5 R(CRUD) の実装)
記事の構成
今回の記事
今回は、全体の記事について記述します。また、とりあえずローカルで
$ rails server
コマンドが動くところまで記述します。次回の記事
Docker を用いた開発を行う上での下準備をおこなっていきます。
主に扱うもの
- Ruby(ver. 2.6.1) + Ruby on Rails(ver. 5.2.2)
- Docker + Docker-Compose(コンテナ 関連)
- MySQL + MySQL Workbench + Sequel Pro + Ridgepole (DB 関連)
- Rspec + Factory Girl + Shoulda Matcher(テスト 関連)
Rails プロジェクトの作成
Version
先述のとおり、Ruby / Ruby on Rails の各 Version は、以下の通りです。
rails new
以下のコマンドを実行しましょう。( DBには、MySQL を使用し 、 API モードで 、 Minitest は使わない ようにするオプション。)
$ rails new rails_api_sample --database=mysql --api -T
$ cd rails_api_sample
Gemfile の編集
今回扱う Gemfile は、以下のようにしています。
source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.6.1' gem 'rails', '5.2.2' # DB(MySQL) の設定に必要な gem gem 'mysql2' # JSON の管理に必要な gem gem 'jbuilder' # 'rails server' 起動時に必要な gem gem 'bootsnap', require: false gem 'puma' # CORS の設定に必要な gem gem 'rack-cors' # Migration の管理に必要な gem gem 'ridgepole' # Trailblazer を扱うのに必要な gem gem 'reform-rails' gem 'trailblazer-loader' gem 'trailblazer-rails' group :development, :test do # 便利コマンド 'binding.pry' を使用するのに必要な gem gem 'pry-byebug' gem 'pry-doc' gem 'pry-rails' # ソースコードが綺麗かどうか Check する gem gem 'rubocop' end group :development do # ファイルの変更を監視する gem gem 'listen' # 起動を早くするために必要な gem gem 'spring' gem 'spring-watcher-listen' end group :test do # TEST 用 DB の管理をする gem gem 'database_rewinder' # TEST 用 データの管理をする gem gem 'factory_bot_rails' gem 'faker' # Rspec で TEST をするために必要な gem gem 'rspec-json_matcher' gem 'rspec-rails' gem 'rspec_junit_formatter' # モデルの関連を TEST するために必要な gem gem 'shoulda-matchers' endbundle install
以下のコマンドを実行しましょう。( vendor/bundle 配下にインストール するオプション。)
$ bundle install --path vendor/bundle
rails server
以下のコマンドを実行しましょう。( $ rails s は $ rails server の省略コマンド。 -p はポート指定。-b はIP Address指定。-e は環境指定。)
$ bundle exec rails s -p 3000 -b '127.0.0.1' -e 'development'
以下のようになったら、とりあえず完了です!( curl コマンド 等で確認してもおそらく DB 周りの設定ができていないのでちゃんとはかえってこないです…。)
おわりに
今回は、とりあえず
$ rails server
コマンドまでを行いました。次回は、Rails で Web API 開発(Part. 2 Docker 関連)を行います。
- 投稿日:2019-02-28T18:56:02+09:00
日本語訳 NEO Smart Contract Workshop Part 1
Dockerを使用してNEO-Pythonの環境を作るNEOのワークショップ Part1の和訳です。
NEOで開発を始めたい方々の参考になれば幸いです。0. 下準備
まず、次の環境が揃っているのか確認してみましょう。
1. Linux/Mac Operating System
2. Docker
3. Python3.6
4. leveldb次に、自分のPCにDockerを入れる際には次のコマンドをターミナルで順番に実行しましょう。
sudo apt-get install curl
sudo curl -sSL https://get.docker.com/ | sh
sudo apt-get update && apt-get upgrade
sudo service docker start最後に、自分のPCにPythonを入れる際に次のコマンドをターミナルで順番に実行しましょう。
sudo apt-get install software-properties-common python-software-properties
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python3.6 python3.6-dev python3.6-venv libleveldb-dev libssl-dev g++1. はじめる
次にローカルのプライベート・ブロックチェーンをセットします。
下の2つの手順によってスマートコントラクトのアップロードと実行ができるようになります。
1. Dockerのコンテナをセットする
2. NEO Pythonを起動する1-1. Dockerのコンテナをセットする
次のコマンドによってDocker Hubから最新のイメージをプルしましょう。
docker pull cityofzion/neo-privatenet
もしこれが初めて行う作業であれば、少し時間がかかるのでしばらく待ちましょう。
Docker Hubからのイメージのプルが完了したら、次のコマンドでコンテナを起動しましょう。
docker run --rm -d --name neo-privatenet -p 20333-20336:20333-20336/tcp -p 30333-30336:30333-30336/tcp cityofzion/neo-privatenet
そして、次のコマンドでコンテナの中に入りましょう。
docker exec -it neo-privatenet /bin/bash.
(ちなみに起動したコンテナを止めるコマンドは次のようなものになります。)
docker rm -f neo-privatenet
1-2. NEO Python を起動する
(もしgitをもっていない場合は、次のコマンドを実行してgitをインストールしましょう。)
sudo apt-get install git
まずNEO Pythonのリポジトリを[ https://github.com/CityOfZion/neo-python/releases/tag/v0.7.1] からダウンロードしましょう。
ダウンロードしたフォルダーをUnzipした後、ターミナルで次のコマンドを実行しましょう。
cd neo-python-0.7.1
次にターミナルの新しいウィンドウを開いて、次のコマンドを順番に実行しましょう。
sudo python3.6 -m venv venv
source venv/bin/activate
そして次のコマンドを順番に実行して、NEO Pythonをインストールしましょう。
sudo pip install -r requirements.txt
sudo pip install -e
その後次のコマンドを実行してNEO Pythonを起動しましょう。
np-prompt -p
ここまでくれば、DockerのコンテナのセットとNEO Pythonの起動の両方は完了です。
Part2 からは、NEO Pythonが起動している状態を前提として進めていきます。
補足とトラブルシューティング
Python3.6、 leveldb、NEO PythonはDockerイメージに含まれるので、Dockerコンテナ内に入ってしまえばインストール不要だということが指摘されます。
Windowsで開発を行う際にローカルにNEO-Pythonをいれられない場合、コンテナ内で作業する形をとったほうがよいかもしれません。
これを踏まえてよりシンプルな環境構築を説明しているのがこちらの記事になりますのでぜひご覧ください。
neo-pythonの環境構築 (Docker使用)
参考資料
NEO Smart Contract Workshop (Part 1)
日本人技術者向けの技術書「Starting NEO」
Keymakers(NEOの日本人開発者コミュニティ)のMedium
- 投稿日:2019-02-28T18:23:06+09:00
AWS Cloud9の標準Dockerイメージからコンテナを起動しようとするとExited (1)となる
AWS Cloud9で新規作成した環境に標準で用意されているDockerイメージを使ってみようとしたが上手くいかず調査したときのメモ。
AWS Cloud9の環境にはDockerが既定でインストールされており、下記の4つのイメージが標準で作成されている。
これでコンテナを作って使えないかと考えた。ec2-user:~/environment $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE lambci/lambda python2.7 b92d1404520d 3 weeks ago 951MB lambci/lambda nodejs6.10 6d5686f02fe2 3 weeks ago 996MB lambci/lambda nodejs4.3 ce68cbe2ecf8 3 weeks ago 945MB lambci/lambda python3.6 659e6b066789 3 weeks ago 1.08GBしかし、runコマンドでイメージからコンテナを起動しようとすると、立ち上がってすぐにExited (1)となりコンテナが落ちてしまう。
ec2-user:~/environment $ docker run -itd b92d1404520d 7cc7c4396751e98e3f6ec1761041d0ed3f978fe5b7a5db57cb6f70d59b825292 ec2-user:~/environment $ docker run -itd 6d5686f02fe2 86e6cb64fa4a6af7640bb3158f0cbb3cf163bc40188e7f1ff3c717265113e50a ec2-user:~/environment $ docker run -itd ce68cbe2ecf8 f9ea26de0f5edd86a0e7c413b979a34dd7ae69c5346f92c694bd1d1f29501fc0 ec2-user:~/environment $ docker run -itd 659e6b066789 a32d9cf3042cbdf0a627fc445e3c39db7ea443ff624f5fd9d405f0edeab91449 ec2-user:~/environment $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a32d9cf3042c 659e6b066789 "/var/lang/bin/pytho…" 10 seconds ago Exited (1) 3 minutes ago keen_galileo f9ea26de0f5e ce68cbe2ecf8 "/usr/local/lib64/no…" 10 seconds ago Exited (1) 3 minutes ago reverent_tereshkova 86e6cb64fa4a 6d5686f02fe2 "/var/lang/bin/node …" 10 seconds ago Exited (1) 3 minutes ago vigorous_swanson 7cc7c4396751 b92d1404520d "/usr/bin/python2.7 …" 10 seconds ago Exited (1) 3 minutes ago infallible_ardinghelli--no-truncオプションでコンテナ起動時に実行されるCOMMANDを全文表示してみると、どうやらAWS Lambdaが関数を実行するときのコマンド実行シーケンスのように見える。(http://marcy.hatenablog.com/entry/2016/12/14/115953)
ec2-user:~/environment $ docker ps -a --no-trunc CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a32d9cf3042c(略) 659e6b066789 "/var/lang/bin/python3.6 /var/runtime/awslambda/bootstrap.py" 7 minutes ago Exited (1) 7 minutes ago keen_galileo f9ea26de0f5e(略) ce68cbe2ecf8 "/usr/local/lib64/node-v4.3.x/bin/node --expose-gc --max-executable-size=160 --max-semi-space-size=150 --max-old-space-size=2547 /var/runtime/node_modules/awslambda/index.js" 7 minutes ago Exited (1) 7 minutes ago reverent_tereshkova 86e6cb64fa4a(略) 6d5686f02fe2 "/var/lang/bin/node --expose-gc --max-executable-size=160 --max-semi-space-size=150 --max-old-space-size=2547 /var/runtime/node_modules/awslambda/index.js" 7 minutes ago Exited (1) 7 minutes ago vigorous_swanson 7cc7c4396751(略) b92d1404520d "/usr/bin/python2.7 /var/runtime/awslambda/bootstrap.py" 8 minutes ago Exited (1) 8 minutes ago infallible_ardinghellidocker logsでログを見てみる。
これは明らかにAWS Lambda関数の実行に失敗したときのエラー。ec2-user:~/environment $ docker logs a32d9cf3042c START RequestId: 010a633a-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST Unable to import module 'lambda_function': No module named 'lambda_function' END RequestId: 010a633a-xxxx-xxxx-xxxx-xxxxxxxxxxxx REPORT RequestId: 010a633a-xxxx-xxxx-xxxx-xxxxxxxxxxxx Duration: 1 ms Billed Duration: 100 ms Memory Size: 1536 MB Max Memory Used: 19 MB {"errorMessage": "Unable to import module 'lambda_function'"} ec2-user:~/environment $ docker logs f9ea26de0f5e START RequestId: 6da74752-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST Unable to import module 'index': Error at Function.Module._resolveFilename (module.js:325:15) at Function.Module._load (module.js:276:25) at Module.require (module.js:353:17) at require (internal/module.js:12:17) END RequestId: 6da74752-xxxx-xxxx-xxxx-xxxxxxxxxxxx REPORT RequestId: 6da74752-xxxx-xxxx-xxxx-xxxxxxxxxxxx Duration: 9.35 ms Billed Duration: 100 ms Memory Size: 1536 MB Max Memory Used: 22 MB {"errorMessage":"Cannot find module '/var/task/index'","errorType":"Error","stackTrace":["Function.Module._load (module.js:276:25)","Module.require (module.js:353:17)","require (internal/module.js:12:17)"]} ec2-user:~/environment $ docker logs 86e6cb64fa4a START RequestId: 64047b49-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST Unable to import module 'index': Error at Function.Module._resolveFilename (module.js:469:15) at Function.Module._load (module.js:417:25) at Module.require (module.js:497:17) at require (internal/module.js:20:19) END RequestId: 64047b49-xxxx-xxxx-xxxx-xxxxxxxxxxxx REPORT RequestId: 64047b49-xxxx-xxxx-xxxx-xxxxxxxxxxxx Duration: 9.66 ms Billed Duration: 100 ms Memory Size: 1536 MB Max Memory Used: 27 MB {"errorMessage":"Cannot find module '/var/task/index'","errorType":"Error","stackTrace":["Function.Module._load (module.js:417:25)","Module.require (module.js:497:17)","require (internal/module.js:20:19)"]} ec2-user:~/environment $ docker logs 7cc7c4396751 START RequestId: cc72da4b-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST Unable to import module 'lambda_function': No module named lambda_function END RequestId: cc72da4b-xxxx-xxxx-xxxx-xxxxxxxxxxxx REPORT RequestId: cc72da4b-xxxx-xxxx-xxxx-xxxxxxxxxxxx Duration: 0 ms Billed Duration: 100 ms Memory Size: 1536 MB Max Memory Used: 14 MB {"errorMessage": "Unable to import module 'lambda_function'"}どうやら私が使おうとしていたDockerイメージは、AWS Cloud9の本来の機能としてAWS Lambda関数の作成、テスト、デプロイを行う際に使用されるイメージで、正規の使い方ではないことをしようとしていたためエラーで落ちてしまっていた、ということでした。
https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/tutorial-lambda.html
結論として、Cloud9上でDockerを利用したい場合は、外部からpullするか、いちからbuildしましょう。
- 投稿日:2019-02-28T16:03:35+09:00
LaravelアプリケーションをAWS上のDockerで動かす
概要
LaravelのアプリケーションをAWS上のDockerで動かすための環境を構築します。
具体的には、以下を行います。
- コンテナを構築するためのDockerfileを作成する
- ECRリポジトリの作成 → AWS CLIで作成
- 1.で作成したDockerイメージをECRにをpushする
- ECSの環境構築 → マネジメントコンソールから作成
前提条件
- AWS CLIがインストールがインストールされていること
コンテナを構築
php
とnginx
の2つのコンテナを構築します。Dockerfileは、それぞれ下記の通りです。phpコンテナのDockerfile
必要なソースコードをコンテナ内にコピーし、依存ライブラリのインストールを行なっています。
FROM php:7.2.10-fpm-alpine COPY . . WORKDIR /var/www/html RUN set -x && \ apk update && \ apk add --no-cache libxml2 libxml2-dev curl curl-dev autoconf $PHPIZE_DEPS && \ docker-php-ext-install opcache mysqli pdo pdo_mysql xml mbstring curl session tokenizer json && \ curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer && \ composer global require hirak/prestissimo && \ composer install && \ chmod -R a+w storage/ bootstrap/cache COPY ./docker/php/config/php.ini /usr/local/etc/php/php.ini COPY ./docker/php/config/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/docker-php-ext-opcache.ininginxのDockerfile
default.conf
の設定を行なっています。
public
ディレクトリ配下は、nginx
コンテナに配置しています。FROM nginx:1.15.5-alpine ADD ./docker/nginx/config/default.conf /etc/nginx/conf.d/default.conf RUN mkdir -p /var/www/html/public ADD ./public/ /var/www/html/public
.dockerignore
の追加Dockerのイメージを小さくするために、
.dockerignore
を追加します。
node_modules
のような容量が大きいものは追加しておく方がいいと思います。
.dockerignore
については、下記の記事に詳しく説明されていますので載せておきます。
.dockerignore アンチパターンECRにDockerイメージをpushする
ECRとは
ECR(Amazon Elastic Container Registry)は、Dockerのコンテナイメージを保存しておくためのレジストリサービスです。ECRに保存したコンテナイメージは、Amazon ECSへのデプロイが可能であったり、他の AWS サービスと簡単に連携することができます。
事前準備
AWS CLIを使用して、ECR用のプロファイルを作成します。
$ aws configure --profile ecrリポジトリ作成
php
とeginx
の2つのリポジトリを作成します。$ aws ecr create-repository --repository-name php --profile ecr $ aws ecr create-repository --repository-name nginx --profile ecrマネジメントコンソールで作成する場合は、以下の通りです。
Amazon ECR
>Repositories
を選択し、リポジトリの作成
をクリックします。
リポジトリ名を入力し、
リポジトリの作成
をクリックして、リポジトリを作成します。
nginx/phpコンテナのビルド
上記で作成したリポジトリ名と同じになるように、dockerイメージ名を指定しビルドします。
タグにはlatest
としていますが、必要に応じて変更してください。$ docker build -t {AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/php:latest -f docker/php/Dockerfile . $ docker build -t {AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest -f docker/nginx/Dockerfile .以下の通りDockerイメージが作成されているはずです。
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ************.dkr.ecr.ap-northeast-1.amazonaws.com/php latest e7cc55e81372 23 seconds ago 376MB ************.dkr.ecr.ap-northeast-1.amazonaws.com/nginx latest c9bfc2840cbc 3 minutes ago 18.2MBECRにログイン
ECRにログインする為のパスワードを取得します。
$ aws ecr get-login --region ap-northeast-1 --no-include-email --profile ecr以下のコマンドが表示されるので、全てコピペし、
docker login
でログインします。docker login -u AWS -p password https://{AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com
Login Succeeded
と表示されればログイン成功です。
~/.docker/config.json
を確認するとauths
に追加されていることが確認できます。~/.docker/config.json"auths": { "{AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com": {} },ECRへDockerイメージをpush
上記で作成したリポジトリにDockerイメージをpushします。
$ docker push {AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/php:latest $ docker push {AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latestECSの環境構築
セキュリティグループの作成
ECSを構築する前に、以下を実現するためのセキュリティグループを2つ作成します。
- インターネットからALBの 443/tcp に対するアクセス許可
- ALBからphpコンテナの 80/tcp に対するアクセス許可
ALBのセキュリティグループ
- 外部から 443/tcp へのアクセス許可
以降の手順で作成するALBを割り当てます。
ECSサービスのセキュリティグループ
- ALBのセキュリティグループから 80/tcp へのアクセス許可
ECSサービスのセキュリティグループとしてますが、実際にはECSでクラスターを作成する際にEC2インスタンスに割り当てるセキュリティグループです。
ALBを作成する
通常のALB作成手順に従ってください。
セキュリティグループは、上記で作成したALBのセキュリティグループを割り当てます。ALBを利用せずにECSをPublicサブネットに配置する場合は、作成する必要はありません。
これ以降、ECSの構築を行なっていきます。
タスクを定義する
コンテナの起動方法をタスクの定義として登録します。
phpコンテナとnginxンテナの組み合わせを定義していきます。
Amazon ECS
>タスク定義
から、新しいタスク定義の作成
を選択します。
起動タイプは、EC2
を選択します。タスクとコンテナの定義の設定
項目 値 タスク定義名 sample-api タスクロール なし ネットワークモード default 補足:
タスクロールは、コンテナ内から他のサービスにアクセスするためのロール設定です。
ネットワークモードについては、下記の記事にわかりやすくまとめられていましたので、掲載します。
ECSでEC2インスタンスを利用する際のネットワークモードについて調べてみた | DevelopersIO次に、コンテナの定義で、phpコンテナとnginxコンテナを追加します。
phpコンテナを追加
項目 値 コンテナ名 php イメージ {AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/php:latest 作業ディレクトリ /var/www/html メモリ制限(MB) ハード制限 300(MB) nginxコンテナを追加
項目 値 コンテナ名 nginx イメージ {AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest メモリ制限(MB) ハード制限 300(MB) リンク php ポートマッピング tcp 80:80 以上で設定は完了です。
作成
を押下して、タスクの定義を作成します。ECSクラスタを作成する
Amazon ECS
>クラスター
から、クラスターの作成
を選択します。
クラスターテンプレートの選択
は、EC2 Linux + ネットワーキング
を使用します。インスタンスの設定
項目 値 クラスター名 sample-api-cluster EC2 インスタンスタイプ t2.micro プロビジョニングモデル スポット スポットインスタンスの配分戦略 最低価格 インスタンス数 1 Maximum bid price (per instance/hour) 10($) 補足:
スポットインスタンスは中断される可能性があります。中断できないアプリケーションに対しては、スポットインスタンスを使用しないことをお勧めします。
クラスターの作成 - Amazon Elastic Container Servicesshログインを可能とする場合、キーペアを指定している必要があります。
この場合、セキュリティグループで22番ポートも解放してください。ネットワーキング
VPCは、ALB作成で指定したVPC指定。
セキュリティグループは、作成済みのECSサービスのセキュリティグループを指定。コンテナインスタンス IAM ロール
デフォルトで選択されているecsInstanceRole
を指定。スポット群 IAM ロール
デフォルトで選択されているecsSpotFleetRole
を指定。以上で設定は完了です。
作成
を押下して、クラスタを作成します。
クラスタが作成されると、コンテナが起動するEC2インスタンスが作成されます。サービスを作成する
Amazon ECS
>クラスター
>サービスタブ
から、作成
を選択します。
項目 値 起動タイプ EC2 タスク定義 sample-api クラスタ sample-api-cluster サービス名 sample-api サービスタイプ REPLICA タスクの数 1 Elastic Load Balancing(オプション)
項目 値 ELB タイプ Application Load Balancer サービス用の IAM ロールの選択 デフォルトで選択されているecsServiceRoleを選択 ELB 名 作成したALBを選択 負荷分散用のコンテナ
nginx:80:80
を指定し、ELBへの追加
を選択。
ターゲットグループ名に、作成したALBに紐づくターゲットグループを選択
を選択。以上で、ECSの環境構築は完了です。
動作確認
作成したALBの
DNS名
にアクセスし、動作確認を行います。Fargateに移行
この記事で作成した環境をFargateに変更する手順を簡単にまとめました。
ECSのバックエンドをEC2からFargateに変更参考記事
下記を参考にさせていただきました。
【AWS】初めてのECR
LaravelアプリケーションをローカルでもAWSでもDockerで動かす
- 投稿日:2019-02-28T13:37:31+09:00
ECSでfluentdを使ってコンテナ毎にlogging
背景
nginx -> appという流れのコンテナを組んでいます。
nginxはawslogsドライバを使って、cloudwatchにログを流しても全然問題無いんですが、appコンテナは諸事情でそうもいかない背景があり、fluentd経由でcloudwatchにログを送りたいと考えました。願望
- コンテナ内でlogrotationの設定はしたくない。
- cloudwatchのログストリーム名はコンテナ毎にユニークにしたい。
- FluentdコンテナをECSで起動する
つくるもの
下記の図のようなものをつくります。
やること
- ECSでfluentd log driverを使うための起動テンプレートの設定
- appコンテナ、nginxコンテナからfluentdコンテナに送らるログをユニークにする
ECSでfluentd log driverを使うための起動テンプレートの設定
EC2インスタンス内で動くecsの設定が下記になる必要があります。
設定ファイルは/etc/ecs/ecs.config
にあります。ECS_CLUSTER=クラスター名 ECS_AVAILABLE_LOGGING_DRIVERS=["awslogs","fluentd","gelf","json-file","journald","splunk"]これを、EC2の起動時に設定できるように、ユーザーデータ等にわたすようにしています。
ECS_AVAILABLE_LOGGING_DRIVERS
を設定しないとコンテナが起動しなかったの注意です。cloudwatchのログストリーム名はコンテナ毎にユニークにしたい
このようなECSの設定をしています。
下記のようすることでCloudwatchのログストリーム名はコンテナ毎にユニークになります。
app.{{.Name}}.{{}.ID}FluentdコンテナをECSで起動する
起動するECSインスタンスそれぞれにfluentdコンテナはいてほしいので
DAEMON
で起動します。(おまけ)docker-composeでは
こんな書いてます。
nginx: ~ 省略 ~ logging: driver: "fluentd" options: fluentd-address: "localhost:24224" fluentd-async-connect: "true" tag: "nginx.{{.Name}}.{{.ID}}" fluentd: ~ 省略 ~ ports: - "24224:24224"(おまけ)fluentコンテナの設定
まずベースとなるイメージはfluentd公式のイメージを使っています。
https://hub.docker.com/r/fluent/fluentd/Dockerfileは下記の用に書き換えています。
特にcloudwatch-logsのプラグインをいれている部分が重要です。Dockerfile
FROM fluent/fluentd:v1.3.3-debian-1.0 # https://hub.docker.com/r/fluent/fluentd # Use root account to use apk USER root RUN buildDeps="sudo make gcc g++ libc-dev ruby-dev" \ && apt-get update \ && apt-get install -y --no-install-recommends $buildDeps \ && sudo gem install \ fluent-plugin-elasticsearch \ fluent-plugin-cloudwatch-logs \ fluent-plugin-stdin \ && sudo gem sources --clear-all \ && SUDO_FORCE_REMOVE=yes \ apt-get purge -y --auto-remove \ -o APT::AutoRemove::RecommendsImportant=false \ $buildDeps \ && rm -rf /var/lib/apt/lists/* \ /home/fluent/.gem/ruby/2.3.0/cache/*.gem RUN apt-get update && apt-get install -y uuid-runtime logrotate gzip COPY fluent.conf /fluentd/etc/fluent.conf
/fluentd/etc/fluent.conf
の内容はこんなかんじです。
(fluentd初心者)<source> type forward port 24224 </source> <match app.**> @type cloudwatch_logs log_group_name /fluentd/my_container/ auto_create_stream true localtime true include_time_key true use_tag_as_stream true use_log_stream_name_prefix true </match> <match nginx.**> @type cloudwatch_logs log_group_name /fluentd/my_container/ auto_create_stream true localtime true include_time_key true use_tag_as_stream true use_log_stream_name_prefix true </match>
- 投稿日:2019-02-28T13:25:40+09:00
MastodonをAWS+オレオレ証明書で動かしてみる
概要
自分の勉強がてらAWSインスタンスにMastodonを設定してみる。SSL必須のようなのだが、恒常的に動かすつもりがないので、オレオレ証明書でとりあえず動かしてみる。当然ながら、このまま利用するのはセキュリティ的に問題なのでご承知頂きたい。
参考サイト
以下のサイトの情報を参考にした。
Dockerで雑にMastodonを起動する方法
AWSでMastodonインスタンスを作るまで。自分まとめ
今何かと話題のマストドン(mastodon)鯖を自分用に無料で立てる方法
Docker+MacでMastodonインスタンスをローカルで構築する
自己署名証明書でnginxをSSL化構築手順
1. AWSでEC2インスタンスを作成
手順は省略。
とりあえずOSはUbuntu18.04,インスタンスタイプはt2.medium,ボリュームサイズは20GBで設定。セキュリティグループはssh(22)とHTTPS(443)をインバウンドに設定しておく。2. スワップファイルの作成
インスタンスタイプはt2.micro程度だとメモリが足りないようなので、スワップファイルを作成する。ただし、dockerコンテナのbuildに無茶苦茶かかるので、buildまではインスタンスタイプを高くしておく手もある。
$ sudo fallocate -l 4G /swapfile $ sudo chmod 600 /swapfile $ sudo mkswap /swapfile $ sudo swapon /swapfile $ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab3.ミドルウェアのインストール
必要なパッケージを入れていく。
$ sudo apt-get update $ sudo apt-get install -y python3-pip unzip docker.io nginx $ sudo pip3 install docker-compose4.Mastodonを設定する
MastodonをGithubから取得する。とりあえず、ホームディレクトリ直下へ。
バージョンによって出来ることの差が激しいので構築するバージョンを固定する。
作成時点で最新のtagであるv2.7.3に切り替える。$ git clone https://github.com/tootsuite/mastodon.git $ cd mastodon $ git checkout -b v2.7.3 refs/tags/v2.7.3ここで、永続化するためにdocker-compose.ymlの編集する例が多いが、v2.7.3では既に編集済みだったので、初期状態のままで大丈夫。
永続化用のディレクトリを作っておく。作成場所はdocker-compose.ymlと同階層。
$ mkdir postgres $ mkdir redisDockerイメージを作成する。インスタンスタイプによってはすごく時間がかかる。
$ docker-compose build
その間にSSLの設定用に秘密鍵とオレオレ証明書を作成する。
5.SSLの設定
オレオレ証明書の作成
opensslを使って証明書を作成する。Ubuntu18.04にはプレインストールされていたが、なければインストールする。
オレオレ証明書はオレオレ認証局(ca)から発行する。そのため、まずは認証局を作る必要がある。認証局の秘密鍵(ca.key)を作成してから、認証局の証明書(ca.crt)を作成する。
証明書の有効期限は10年 (3650日)とする。証明書作成は対話式なので好きな値を入れよう。未設定でも構わない。$ mkdir certs $ cd certs $ openssl genrsa -out ca.key 2048 $ openssl req -new -x509 -days 3650 -key ca.key -out ca.crt次にngnixに設定するオレオレサーバ証明書(mastodon.crt)を作成する。
秘密鍵(mastodon.key)を作って、その後認証局に依頼するための署名要求ファイル(mastodon.csr)を作成する。ここも対話式になるので、少なくともOUとCNは入力する。(ここではOU=example, CN=example.com)
最後に署名要求ファイルに認証局が署名してサーバ証明書(mastodon.crt)を作る。$ openssl genrsa -out mastodon.key 2048 $ openssl req -new -key mastodon.key -out mastodon.csr $ openssl x509 -req -days 3650 -CA ca.crt -CAkey ca.key -CAcreateserial -in mastodon.csr -out mastodon.crtnginxの設定
nginxの設定ファイルを編集する。先ほど作成したサーバ証明書と秘密鍵は
ssl_certificate,ssl_certificate_keyにパス付で指定する。$ sudo vim /etc/nginx/sites-enabled/default以下の内容に入れ替える。
/etc/nginx/sites-enabled/defaultmap $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; listen [::]:80; server_name localhost:3000; root /home/ubuntu/mastodon/live/public; # Useful for Let's Encrypt #location /.well-known/acme-challenge/ { allow all; } #location / { return 301 https://$host$request_uri; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name localhost:3000; ssl_protocols TLSv1.2; ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_certificate /home/ubuntu/mastodon/certs/mastodon.crt; ssl_certificate_key /home/ubuntu/mastodon/certs/mastodon.key; keepalive_timeout 70; sendfile on; client_max_body_size 80m; root /home/ubuntu/mastodon/live/public; gzip on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; add_header Strict-Transport-Security "max-age=31536000"; location / { try_files $uri @proxy; } location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) { add_header Cache-Control "public, max-age=31536000, immutable"; try_files $uri @proxy; } location /sw.js { add_header Cache-Control "public, max-age=0"; try_files $uri @proxy; } location @proxy { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_set_header Proxy ""; proxy_pass_header Server; proxy_pass http://127.0.0.1:3000; proxy_buffering off; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; tcp_nodelay on; } location /api/v1/streaming { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_set_header Proxy ""; proxy_pass http://127.0.0.1:4000; proxy_buffering off; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; tcp_nodelay on; } error_page 500 501 502 503 504 /500.html; }nginxを再起動する。
$ sudo systemctl start nginx6.再びMastodonの設定
以下のコマンドを2回打って、出力された文字列をどこかに記録しておく。
$ cd ~/mastodon $ docker-compose run --rm web rake secret次に環境設定ファイルを作る。テンプレートがあるのでそれをコピーして作成する。
$ cp .env.production.sample .env.production $ sudo vi .env.production以下のSECRET_KEY_BASE, OTP_SECRETに先ほどの文字列を設定する。
.env.production20 LOCAL_DOMAIN=localhost:3000 34 # Application secrets 35 # Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose) 36 SECRET_KEY_BASE= 37 OTP_SECRET=Databaseを作成する。
$ docker-compose run --rm web rails db:migrateアセットを作成する。
$ docker-compose run --rm web rails assets:precompileMastodonのコンテナを起動する。docker-compose psできちんと立ち上がっているか確認しよう。
$ docker-compose up $ docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------------- mastodon_db_1 docker-entrypoint.sh postgres Up (healthy) mastodon_redis_1 docker-entrypoint.sh redis ... Up (healthy) mastodon_sidekiq_1 /tini -- bundle exec sidekiq Up mastodon_streaming_1 /tini -- yarn start Up (unhealthy) 127.0.0.1:4000->4000/tcp mastodon_web_1 /tini -- bash -c rm -f /ma ... Up (unhealthy) 127.0.0.1:3000->3000/tcpMastodonに接続する
以上で完了。ChromeかEdgeあたりのWebブラウザで接続する。
FireFoxはオレオレ証明書のサイトは見れないので他のブラウザを使う。https://EC2インスタンスのパブリックDNS or パブリックIP/about
- 投稿日:2019-02-28T12:10:41+09:00
Dockerの基本コマンド
外部からイメージを持ってくる場合
$ docker pull ${imageName}$ docker run -itd --name ${contenaName} ${imageName or imageID}
-p
: 外部からアクセスされるポート番号:コンテナ側のポート番号
-v
: ホストの絶対パス:コンテナの絶対パス$ docker exec -it ${contenaName or contenaID} bash or $ docker attach ${contenaName or contenaID}
attach
はexit
時、コンテナが停止する$ docker start ${contenaName or contenaID}$ docker stop ${contenaName or contenaID}$ docker rm ${contenaName or contenaID}$ docker rmi ${imageName or imageID}自分でイメージを作成する場合
dockerfile:
build
の手順書./dockerfileFROM ubuntu CMD echo 'Hello docker world!'
FROM
: imageName
ARG
: 変数定義 -> 代入時: $変数名
RUN
: build時に実行
CMD
: run時に実行$ docker build -t ${imageName or imageId} ${dockerfileName} ${absolute path}コンポーズ(イメージ作成からコンテナ起動まで行ってくれる)
Docker Composeのインストール
$ curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-composechmod +x /usr/local/bin/docker-compose
docker-Compose
が使用できるか確認$ docker-compose --versionDocker Composeを使ってみる
./dockerfileFROM python:3.6 ARG project_dir=/projects/ ADD src/requirements.txt $project_dir RUN mkdir /test VOLUME /test/ ADD src/requiremnts.txt /test/ ARG requirements=/test/requirements.txt WORKDIR $project_dir RUN pip install -r $requirements./docker-compose.ymlversion: '3' services: flask: build: . ports: - "5000:5000" volumes: - "./src:/projects" tty: true environment: TZ: Asia/Tokyo command: flask run --host 0.0.0.0 --port 5000./src/app.pyfrom flask import Flask, jsonify app = Flask(__name__) app.config['JSON_AS_ASCII'] = False @app.route('/') def index(): return jsonify({ "message": "Hello flask!" }) if __name__ == '__main__': app.run()./src/requirements.txtflask jsonify$ docker-compose up -dアクセスできるかホストから確認
$ curl http://localhost:5000 {"message":"Hello flask!"}参考
Docker | docker build と Dockerfile でイメージをビルドする基本
Python+Flask環境をDockerで構築する
Dockerfileについて
docker-compose.ymlの命令を理解して、よりDockerを有効活用したい!
- 投稿日:2019-02-28T10:50:20+09:00
Windows10にDockerをインストールしてbusyboxコンテナが動くようになるまで
Windows10にDockerをインストールしてbusyboxコンテナが動くようになるまで
ずいぶん罠が多かったので、下記の完成形にあるコマンドが問題なく実行できるようになるまでをメモする。
TL; DR
Docker Desktop for WindowsをWindows10にインストールする場合は
- デフォルトのLinux containersではなくWindows containersを選択する
- Experimental featureを有効化する
- WindowsのHyper-Vとコンテナ機能GUI(コントロールパネル)経由ではなく、CUI(PowerShell)経由で有効化する
と上手くいきそう。
完成形
Dockerのバージョンは下記にある通り
v18.09.2
CE(Stable版)。
後述のように、Experimental featureを有効化する必要があった。> docker version Client: Docker Engine - Community Version: 18.09.2 API version: 1.39 Go version: go1.10.8 Git commit: 6247962 Built: Sun Feb 10 04:12:31 2019 OS/Arch: windows/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 18.09.2 API version: 1.39 (minimum version 1.24) Go version: go1.10.6 Git commit: 6247962 Built: Sun Feb 10 04:28:48 2019 OS/Arch: windows/amd64 Experimental: true > docker run --rm busybox echo hello_world Unable to find image 'busybox:latest' locally latest: Pulling from library/busybox 697743189b6d: Pull complete Digest: sha256:061ca9704a714ee3e8b80523ec720c64f6209ad3f97c0ff7cb9ec7d19f15149f Status: Downloaded newer image for busybox:latest hello_worldただし、この状態になっても、Linux container用のデーモンに切り替える(タスクバーのDocker Desktopアイコンを右クリック→
Switch to Linux containers
)とDocker Desktopの起動に失敗する。環境
- OS: Microsoft Windows 10 Pro
- 認証付きプロキシ内(環境変数のHTTP_PROXYとHTTPS_PROXYに
http://ユーザー名:パスワード@proxy.com:ポート番号
形式で設定済み- ハードウェア: Microsoft Surface Pro 6
手順
Docker Desktop for Windowsのインストール
Docker IDでログインし、普通にStable版をダウンロード&インストールする。
このときデフォルトのLinux containersを選択したが、ここでWindows containerを選択しておくと、下記の起動エラーが起こらなかったように見える。(未検証)
https://hub.docker.com/editions/community/docker-ce-desktop-windows
インストーラーがWindowsのHyper-Vとコンテナ機能を有効にするため、OSが再起動する。
しかし、起動後Docker Desktopが下記のエラーで起動に失敗する:
Unable to start: ユーザー設定変数 "ErrorActionPreference" または共通パラメーターが Stop に設定されているため、実行中のコマンドが停止しました。'MobyLinuxVM' は起動できませんでした。(仮想マシン ID 15E56AF6-2ED1-4955-BEEC-B280F98867F6) Start-MobyLinuxVM、<ファイルなし>: 行 296 <ScriptBlock>、<ファイルなし>: 行 412 場所 Docker.Core.Pipe.NamedPipeClient.Send(String action, Object[] parameters) 場所 C:\workspaces\stable-18.09.x\src\github.com\docker\pinata\win\src\Docker.Core\pipe\NamedPipeClient.cs:行 36 場所 Docker.Actions.<>c__DisplayClass28_0.<SwitchDaemon>b__0() 場所 C:\workspaces\stable-18.09.x\src\github.com\docker\pinata\win\src\Docker.Windows\Actions.cs:行 305 場所 Docker.WPF.TaskQueue.<>c__DisplayClass19_0.<.ctor>b__1() 場所 C:\workspaces\stable-18.09.x\src\github.com\docker\pinata\win\src\Docker.WPF\TaskQueue.cs:行 59PowerShellからのHyper-V・コンテナ機能再有効化
コントロールパネル→プログラムと機能→Windowsの機能の有効化または無効化を選択し、「Hyper-V」と「コンテナ」のチェックを外して再起動する。
再起動後、PowerShellを管理者権限で起動し、以下のコマンドを実行する:
> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All # 再起動を促されるので再起動した後、以下を実施 > Enable-WindowsOptionalFeature -Online -FeatureName Containers -All参考: https://github.com/docker/for-win/issues/1221#issuecomment-337770743
まだDocker Desktopの起動に失敗する。
Hyper-V Virtual Machine Management サービス再起動
PowerShellを管理者権限で起動し、以下のコマンドを実行する:
> net stop vmms > net start vmmsここまでやるとDocker Desktopの起動に成功する。
しかし、
docker version
を実行すると以下のようなエラーメッセージが出る:> docker version Client: Docker Engine - Community Version: 18.09.2 API version: 1.39 Go version: go1.10.8 Git commit: 6247962 Built: Sun Feb 10 04:12:31 2019 OS/Arch: windows/amd64 Experimental: false error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.39/version: 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.PowerShellからのDocker Daemon切替(Linux→Windows)
どういうわけか、CLI経由でDaemonをLinuxコンテナ用からWindowsコンテナ用に切り替えるとエラーが解消されるらしい:
> cd "C:\Program Files\Docker\Docker" > ./DockerCli.exe -SwitchDaemon参考: https://github.com/docker/for-win/issues/1825#issuecomment-433719346
確かに
docker version
してもエラーは出なくなったが、Linuxコンテナは実行できない。> docker run --rm busybox echo hello_world Unable to find image 'busybox:latest' locally latest: Pulling from library/busybox docker: no matching manifest for unknown in the manifest list entries. See 'docker run --help'.Docker DaemonのExperimental Feature有効化
タスクバーのDocker Desktopアイコンを右クリックし、Settingsを選択する。
DaemonメニューのBasicとなっているスイッチをAdvancedにスライドする。
参考: https://halkichi-web.hatenablog.com/entry/2018/08/23/124454Docker再起動後、問題なくbusyboxコンテナが実行できることを確認:
> docker run --rm busybox echo hello_world Unable to find image 'busybox:latest' locally latest: Pulling from library/busybox 697743189b6d: Pull complete Digest: sha256:061ca9704a714ee3e8b80523ec720c64f6209ad3f97c0ff7cb9ec7d19f15149f Status: Downloaded newer image for busybox:latest hello_world他のコンテナも実行可能:
> docker run --rm -it ototadana/nlp-jp bash Unable to find image 'ototadana/nlp-jp:latest' locally latest: Pulling from ototadana/nlp-jp 8ad8b3f87b37: Pull complete 1ea481c977b3: Pull complete c49f1fa31376: Pull complete 2840b8cb5b3f: Pull complete 3da718da5013: Pull complete 8901c1789308: Pull complete b6c16d69e588: Pull complete b63e6e3a5fee: Pull complete 49c57988feb4: Pull complete 8c4df89b9522: Pull complete 3838b41d340b: Pull complete Digest: sha256:c26ffe74a2ead80906ed3fc3b9b1a384f6a6235da93299f890ed1eebf5dcbf92 Status: Downloaded newer image for ototadana/nlp-jp:latest root@3099d19b492a:/#付録: Windowsコンテナにディレクトリをマウントする方法
以下のように
-v
オプションで任意のディレクトリを指定するだけでOK。> docker run -v C:\OS側のディレクトリパス:/コンテナ上のマウント先 -it --rm ubuntu bashWeb検索すると「Docker DesktopのSettingsからShared Volumeを設定する」という文言が出てくるものの、Shared Volumeというメニューが無くて焦るが、Shared VolumeはLinuxコンテナを利用しているときの機能らしい。
参考: https://forums.docker.com/t/shared-drives-option-not-showing-up-in-docker-for-windows-settings/35725/4
- 投稿日:2019-02-28T09:05:56+09:00
8年前に作った HTML5 アプリを最近の技術で作り直した話(5年ぶり2回目)
icotile は、HTML5 を活用して iTunes のような操作感で Twitter の友達やリストを管理できる Web アプリケーションです。2011年に最初のバージョンをリリースし、2014年には、AngularJS と Bootstrap で全面的に書き換えた icotile2 をリリースしました。この8年間で延べ 55,000ユーザーに利用されている Web アプリです。
随分ほったらかしにしていたのですが、いまだに意外と使われていて、たまに要望とかもいただいていました。最近プロダクトを作っていなかったので、最新の技術を勉強するために、icotile3 の開発に着手しました。
随分古い技術スタックだったのと、勉強も兼ねているので、できるだけまだ使ったことのない技術を採用してみました。また、サーバサイドの Node.js への置き換えも行って、フロントエンドとバックエンドの共通化も図ってみました。機能はほぼ同等+アルファですが、データベース以外はほぼ置き換えです。
icotile (2011) icotile2 (2014) icotile3 (2019) Front-end
FrameworkjQuery AngularJS 1.x Vue.js / Vuex UI Framework jQuery UI Bootstrap Vuetify Style スキューモーフィック風 フラットデザイン マテリアルデザイン Language JavaScript JavaScript TypeScript Backend PHP / CakePHP PHP / CakePHP NodeJS / Express Database MySQL MySQL MySQL Web Server Apache Apache Apache + nginx Protocol HTTP HTTP HTTPS その他 - - docker / docker-compose での環境構築、PM2 でのプロセス管理等。 関連記事 Twitter の友達やリストを iTunes 風に管理できるアプリ「icotile」(アイコタイル)をリリース 3年ぶりのバージョンアップ!AngularJS などの最新技術で再構築した Twitter リスト管理アプリ「icotile2」リリース! Vue.js/Vuex/Vuetify
Angular は複雑で理解するのに時間がかかったのですが、Vue.js/Vuex は構造がシンプルで、ドキュメントもわかりやすく、どんどん理解できてどんどんコードが書ける感じが気持ちよかったです。
React/Redux は仕事で散々やったので、今回 Vue をトライしてみました。React は、Redux とのつなぎこみが面倒だったので、その辺りは Vuex の方がうまく統合されていてわかりやすかったです。
あと、どちらかというと、UI フレームワークの Vuetify がとても良くできていて、素早く UI 開発ができました。前回は、Angular
と Bootstrap を自分で統合していたのですが、それが一切なく、すぐにマテリアルデザインのアプリが出来上がるのがよかったです。また、今回初のモバイル対応も簡単にできました。TypeScript
TypeScript は部分的に使った感じでしたが、定義したデータ型をフロントエンドとバックエンドで共有して、コンパイル時にエラーをチェックできたのはよかったです。それ以外は結構
any
で逃げた感じ。Node.js/Express
さすがにもう PHP は覚えていないので、Node.js/Express に置き換え。フロントエンドとバックエンドで同じ言語で開発できるのはやっぱり楽ですね。プロセスの管理は PM2 を使用しました。
nginx
フロントエンドと API をルーティングするために、nginx を使ってみました。フロントは、普通に Web サーバとして、ビルドされたスタティックをサーブし、API は Express のローカルサーバへのプロキシとして動かしてます。これが正しいのかは良くわからず...
Docker
一番大変だったのは、Docker での環境構築で、概念を習得するのも、試行錯誤するのも時間がかかりました。いまだに正しい使い方をしているか自信ないですが、ステージングと本番環境をすぐに立ち上げられたり、ローカルで同じ環境で試せるのはよかったです。
あと、PM2 の設定や Bitbucket からの Webhook での更新とか、いろいろトライして、いろいろ勉強になりました。
今後
今回モバイル対応もしたので、Android 向けに PWA でアプリ化したいのと、iOS でネイティブクライアントを作ろうと思っています。MVVM や RxSwift の勉強のために。
と、特にオチもないですが、機能的にも色々進化しているので、Twitter をやってましたら、ぜひ icotile3 をお試しください。