20190228のdockerに関する記事は17件です。

プラグインインストール済の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 \l

Debianのバージョンは8.6

jenkins@df7311076006:/etc$ cat /etc/debian_version
8.6

unameでバージョン確認

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 /                                                                                                                                                                                                                                                                     123MB

javaがopenjdk8.111
JENKINS_HOME=/var/jenkins_home

JENKINS_VERSION=2.19.4

などの設定をしていることがわかる。

以上、興味本位で調べてみた。番外編でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

jupyter/datascience-notebookでPythonのデータ解析環境を構築する

『Software Design 2019年3月号』で「ITエンジニアのための機械学習と微分積分入門」という特集が組まれています。特集の第3章「Pythonで実践する機械学習」ではPythonのコードで簡単なデータ解析のアルゴリズムが解説されています。章の最初にPythonの環境構築の節があり、以下3種類の環境構築の方法が示されています。

  1. 標準のPythonを使う
  2. Anaocndaの利用
  3. Dockerを使う

3番目の「Dockerを使う」方法では、jupyter/datascience-notebookを利用すればサンプルコードを全て実行できるとあります。

本記事では、jupyter/datascience-notebookを使って特集記事のコードを実行する環境を構築する手順をまとめました。

環境構築の手順

概要

手順の概要は以下の通りです。

  1. Dockerをインストールする。
  2. Dockerイメージを取得する。
  3. Dockerイメージを実行する。
  4. データ解析環境にアクセスする。

1. Dockerをインストールする。

最初にDockerをインストールします。

以下はmacOSでHomebrewをインストール済みの場合です。

$ brew cask install docker

2. 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-notebookjupyter/r-notebookに含まれる機能全て
  • Juliaのコンパイラと基本的な環境
  • JuliaのコードをJupyter notebookで実行するためのIJulia
  • HDF5、Gadfly、RDatasetsパッケージ

最後に

上記の手順で構築した環境で特集のサンプルコードを実際に実行できることを確認しました。環境構築にかかった時間はほぼDockerイメージのダウンロード待ちだけでした。同じ環境を自力で構築するのは結構大変だと思います。Dockerの便利さを改めて認識しました。

参考URL

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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)が吸収し、様々なソフトウェアが詰まったコンテナを動作させることで実行環境を構築します。コンテナについては後述します。

image.png
図1 ホスト型仮想化 
image.png
図2 コンテナ型仮想化

Dockerの利点

コンテナ型仮想化ではゲストOSを持たないため以下の利点があります。

  • 処理速度が早い

    ホスト型仮想化ではゲストOSを構成する際にCPUリソースやメモリ、ストレージの割り当てが行われるが、コンテナ型技術ではゲストOSを構成しないためオーバヘッドが非常に少ない。(=消費するリソースが少ない)

  • 起動が早い

    Dockerデーモン(Dockerのアプリのこと)が立ち上がってればよくてゲストOSを構成したりしないから当然早い

  • 可搬性が高い
    Dockerエンジンがあれば動く。要するにどこでも動く

  • イメージが軽い

  • インフラのコード化

    色々やらなくていい

  • 便利機能満載

    コンテナ型仮想化独自のメリットという訳ではないが色々設定できるようになると高機能

メリットをたくさんあげましたが、1点注意点としてLinux系のCentOSやUbuntuなどのコンテナが存在しますが、あれは完全なOSを構築している訳ではなく、あくまでカーネルはホストOSであるという点に注意するべきです。カーネルを共有させるべきコンテナは動作させる事ができません。

コンテナ、Dockerイメージ

Dockerイメージとはコンテナ実行に必要なファイルをまとめたファイルシステムです。AUFSなどの特殊なファイルシステムが使用されています。イメージ上のデータはレイヤで構成されていて読み取り専用となっています。その上に構成されるコンテナレイヤーが読み書き可能なレイヤーです。Dockerイメージ+コンテナレイヤーでコンテナとなるイメージです。図にすると下のような感じ。

image.png
図3 Dockerイメージとコンテナ

具体例をみてみましょう

CentOSのベースイメージを継承してRubyの実行環境のレイヤーを加えています。因みにベースイメージとは何も継承していない基底イメージのことです。

image.png

図4 CentOSベースイメージの継承

作成したRubyの実行環境のイメージをさらに継承してRailsの実行環境も作成できます。

image.png

図5 Rubyの実行環境にRailsのレイヤーを加える例

このようにレイヤーを重ね合わせてイメージを作成します。

次は同じイメージを継承する場合です。この場合、CentOSレイヤーを共有することができます。2重でレイヤーを用意しなくていいのでイメージサイズが小さくなります。さらに差分のイメージだけを取得することになるので、通信量も抑えることができます。

image.png
図6 ベースイメージの共有

Dockerに触れてみる

Dockerのインストールは省略します。わかりやすい記事が豊富にあると思うのでググってみてください。今回はDockerの動作原理などを確認するのが目的です。

1.Dcokerデーモンが起動していることを確認

image.png

図7 Dockerデーモンの起動を確認

Docker is runningとなってればOKです。図3で言うところのコンテナエンジンがこれです。

2.ターミナル上でHello Worldしてみる

Dockerで単純なイメージの取得と動作を確認しましょう。ターミナルを開いて以下のコマンドを入力してみてください。run はその後ろに記述したイメージを取得して実行するサブコマンドです。このコマンドではhell-worldというイメージを取得して実行します。

$ docker run hello-world

image.png

初めて実行したのであれば↓のような結果が返ってくると思います。

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で起動を確認したソフトです。

image.png

図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:コンテナの起動

よく使うコマンドなので少しづつ覚えていきましょう。

今回はここまで。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オフライン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:

DockerDesktop.png

シンプルな解決策

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 ms

terminal.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: active
terminal.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: inactive
terminal.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 ms

host.docker.internalだとレスポンスが早いので通信が閉じた感じなのかな? Dockerはまだまだ落ち着かないので, しっかり追わないと駄目ですね. これでネットワーク難民時にも色々遊べる. ちゃんちゃん.

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 の全体は以下のとおりです。

Dockerfile
FROM 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=on

Go 1.12 では、Go Modules を使用するために必要な環境変数 GO111MODULEon にしています。

RUN apk add --no-cache \
        alpine-sdk \
        git \
    && go get github.com/pilu/fresh

パッケージとして一通りビルドに必要なものが入っている alpine-sdk と Go Modules でライブラリ取得時に内部的に git を利用しているので git をインストールしています。
また、Go 開発のホットリロードで利用する fresh をインストールしています。

EXPOSE 8080

8080 ポートで Listen するアプリケーションなので、EXPOSE 命令で 8080 ポートを明示しています。

CMD ["fresh"]

最後に fresh で起動することで、ホットリロードで起動する Dockerfile の完成です。

docker-compose

開発環境の docker-compose ファイルは以下のとおりです。

docker-compose.yml
version: '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.prod
FROM 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.modgo.sum ファイルをコピーしています。
これは、コピー後に go mod download を実行してライブラリをインストールすることで、次回以降ライブラリの追加、 go.modgo.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 myapp

docker top コマンドで実行ユーザーを確認してみます。

$ docker top myapp
PID                 USER                TIME                COMMAND
13606               10001               0:00                /go/bin/app

USER10001 で実行されていることが分かります。

番外編

本番環境の例では、ビルドステージにデフォルトのイメージを使用して作成しました。
ただし、デフォルトのイメージを採用することによるデメリットも存在します。
以下に示すのは、デフォルトの 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.prod
FROM 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-sdkgit をインストールし、ファイルを全てコピーするように変更しています。

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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
を使用。

まずはユーザ登録、ドメイン取得。
このあたりは参考になるページがいくつもあるので、割愛。
01_freenom.png

こんな感じでドメインとさくら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 docker

sudoグループに追加(sudoを付けなくてもdockerコマンドが使用できるように)

$ sudo groupadd docker
$ sudo usermod -aG docker ユーザ名

※ 「sudo groupadd docker」はすでに存在するため不要のはずだが、念のため。

自動起動の設定

$ sudo systemctl enable docker

OS再起動(念のため)

$ reboot

参考:CentOS7にDockerをインストールする

Docker 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 --remote

docker-compose.ymlの設定

vi docker-compose.yml

5行目を「image: nextcloud:fpm」に変更する。

docker-compose.yml
ersion: '3'
services:
  app:
    container_name: app-server
    image: nextcloud:fpm     ←変更
    stdin_open: true
    tty: true

nginxブロックに「- /etc/letsencrypt:/etc/letsencrypt」を追記する。

docker-compose.yml
  nginx:
    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.conf
    server {
        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-server

http://ドメイン名.com
でサイトにアクセスできることを確認する。
image.png
とりあえずここまででNextCloudの構築は成功。

※ Chromeで一度httpsで接続してしまうと、再構築後もhttpsにリダイレクトされてしまって接続できない現象が発生。その場合、以下を参考にHSTSを削除する。

  Chromeでhttpからhttpsへ強制リダイレクトされる場合の対処法

Let's Encryptの設定

まずはインストール

$ sudo yum install epel-release
$ sudo yum install certbot

nginx.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-le

nginx.confのサーバブロックにSSL証明書の設定を追加する。

vi nginx.conf
nginx.conf
    server {
        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://ドメイン名」でアクセスできること、証明書が有効になっていることを確認する。
image.png

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-server

MariaDBのdockerにログイン

$ docker exec -it mariadb-server bash

MariaDBでデータベース作成など

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にログインできることを確認する。
あなたの全データの安全な家・・・。

image.png

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などが作成可能になっている。

image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[秋葉原] ゼロから始めるKubernetes入門会 #1 (初心者大歓迎!) 後半資料

[秋葉原] ゼロから始めるKubernetes入門会 #1 (初心者大歓迎!)


docker本番で使えるんじゃね?という話

既存の仮想化技術 Docker
分類 ホストOS型の仮想化 コンテナ型仮想化技術
(OS-level virtualization)
オーバヘッド 大きい。
H/WをS/Wエミュレート
小さい。
ホストのH/W使う
環境構築 大変。
手順書通りに
パッケージマネージャを操作
簡便。
Dockerfile書いて
docker buildコマンド叩くだけ
ポータビリティ 低い 高い。
ローカルのを本番へ、
本番のをローカルへ
用途 ローカル検証 本番にも使える

コンテナで本番アプリケーションを作ろう

webapp_monolithic.png

  • アプリケーションは様々なプロセスから成る

webapp_microservice.png

  • ベストプラクティス:
    コンテナは関心事ごとにひとつ
  • 1つのコンテナに全部詰め込まない

webapp_microservice_yabai1.png

  • アクセスめっちゃ増えた!
  • DBは余裕だけどPHPが限界!
    => Nginxとphp-fpm増やす(スケールアウト)

コンテナを複数動かすと

  • いろいろ考えること出てくる
    • どの順番でコンテナ起動する
    • 何番ポートで通信する
  • docker container run直接叩くのはもうむり

Docker Compose

docker_compose.png

  • 複数コンテナをいい感じに動かす
  • 「いい感じに」...ymlファイルで定義できる

限界

docker_compose_rip.png

  • 唯一一台のノードが壊れたら死ぬ(SPOF)
  • 壊れないまでも、性能面で困ったとき
    ハードウェアをスケールアウトできない

コンテナオーケストレーション

  • 複数ノード上で複数コンテナをいい感じに動かす

docker_swarm.png


swarm_vs_kube.jpg

  • 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を起動します
    • 戻し方は知りません

imperative.png


  • 宣言的
    • レプリカ数が1 です
    • レプリカ数が2 です
    • レプリカ数が3 です

declarative.png

  • Immutable Infrastracture + 宣言的設定 = ロールバックしやすい!

1.3 自己回復するシステム

  • 初期化してハイおしまい、ではない
  • まずい状態になったら回復する
    • コンテナが1つ死んで2つになった
      => 1つ新しく生成して3つにする
    • 誰かがいたずらしてコンテナを4つにした
      => 1つ停止して3つにする
  • 宣言的設定ならでは
    • 「こうあってほしい」という状態をダイレクトに表現

2. スケールすること

  • 2.1 サービスのスケール
  • 2.2 開発チームのスケール

2.1 サービスのスケール

  • めっちゃアクセス集中したら
    • ノード(マシン)増やす
    • コンテナ増やす

2.2 開発チームのスケール

  • 人が増えると
    • コミュニケーションコストがやばい
    • 意思決定・目的意識の共有が大変

communications.png

  • 例)n人のチームで2人組のコミュニケーションは
    nC2 = n(n-1)/2 = O(n^2)件

communication_cost.png

  • 2倍の規模のシステム作りたい
  • 2倍の人材を投入しました
  • コミュニケーションコストは4倍になりました

  • サービスを独立性の高い形で小分けにする(microservice pattern)
    • 他サービスとの接続部が明確
    • それ以外の部分は小さなサービスに集中できる
  • 人材も小分けにできる
    • コミュニケーションコスト低くてすむ

communications.png


communications_micro.png


3. インフラの抽象化

  • パブリッククラウドを使ってサービス構築する場合
  • クラウド事業者によって設定の方法とか全然違う

aws.png

clb.png


kube_abstraction.png

  • 各種インフラをKubernetesのリソースとして抽象化
  • オレンジとか青とか消えた

4. 効率性

  • いい感じにコンテナ配置してくれる
  • 物理マシン数節約できる
  • 開発のコスト下げられる

Kubernetesすごい!使いたい!

  • 頑張ってインストールしてください

Kubernetesのdaemon入れる

  • Windows
    • Docker for Desktopについてくる
      • 要 Windows10 PRO
    • チェックボックス入れればすぐ使える
  • macOS
    • やはりチェックボックス入れればすぐ使える
  • linux
    • Minikubeを使ってます
      • 入れるのそこそこめんどくさい。がんばれ

image.png


スクリーンショット 2019-03-01 10.22.30.png


スクリーンショット 2019-03-01 10.27.06.png


スクリーンショット 2019-03-01 10.30.44.png


Kubernetesのclient入れる

  • Windows
  • 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

今日つくるもの


all.png


Kubernetesの世界観

  • ぜんぶ「リソース」
    • コンテナ動かすホスト(マシン): Node
    • Nodeの集合体: Cluster
    • Cluster上で動かす、コンテナの集合体: Pod
    • Podの集合体: ReplicaSet
    • ReplicaSetを外部公開する人: NodePort Service

Nodeリソース

  • 皆さんの目の前にある箱です
    • 正確には、そこで動いているコンテナホスト(dockerd)

Clusterリソース

  • 今回は単ノード

Podリソース

  • コンテナの集合体
    • 1コでもPod
    • 密結合なほうが都合の良い組
      • MySQLのMASTER/SLAVES
      • Webサーバーと、前段のNginx

はじめてのPod

pod.png

  • 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.png

  • 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

Service.png

  • ReplicaSetは複数のPodからなる
  • どれと通信する?
  • 意識しなくていい
    • サービスディスカバリ

NodePort Service

all.png

  • クラスタ外(ホスト)からアクセスできる

マニフェストファイル

  • 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番ポートでアクセスできるよ、ってこと

疎通確認

Hello Docker!!
  • めでたし

後始末

kubectl delete -f simple-nodeport-service.yml
kubectl delete -f simple-replicaset.yml

資料

書籍

絵描いたやつ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails で Web API 開発(Part. 2 Docker 関連)

はじめに

 本記事は、自身が今までの Ruby on Rails で開発してきた知識 / 知見の総まとめをおこなったものです。
 「ここは、もっとこうしたほうがいいよ!こういうものがあるよ!」というようなことがあれば、随時おしらせください!
 最終的なプロダクトは、 Rails API Sample に置いておきます。

各記事

記事の構成

前回の記事

 前回は、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 周りの設定ができていないのでちゃんとはかえってこないです…。)

Screen Shot 2019-02-27 at 16.40.12.png

各種コマンド

 覚えておいたほうがよいコマンドに関して少しだけ記述しておきます。

$ 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 関連)を行います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails で Web API 開発(Part. 1 概要)

はじめに

 現在、執筆中です。
 本記事は、自身が今までの Ruby on Rails で開発してきた知識 / 知見の総まとめをおこなったものです。
 「ここは、もっとこうしたほうがいいよ!こういうものがあるよ!」というようなことがあれば、随時おしらせください!
 最終的なプロダクトは、 Rails API Sample に置いておきます。

対象

  • Mac での開発者
  • ある程度 Rails / Docker の知識があるとよいかな…。と

各記事

記事の構成

今回の記事

 今回は、全体の記事について記述します。また、とりあえずローカルで $ 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 は、以下の通りです。

Screen Shot 2019-02-27 at 12.31.54.png
Screen Shot 2019-02-27 at 12.35.05.png

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'
end

bundle 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 周りの設定ができていないのでちゃんとはかえってこないです…。)

Screen Shot 2019-02-27 at 14.36.50.png

おわりに

 今回は、とりあえず $ rails server コマンドまでを行いました。次回は、Rails で Web API 開発(Part. 2 Docker 関連)を行います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

日本語訳 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

image.png

もしこれが初めて行う作業であれば、少し時間がかかるのでしばらく待ちましょう。

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

おそらく次のような画面になることが多いと思います。
image.png

ここまでくれば、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
  1. Mac(マック)で行うNEO(ネオ)の プライベートネットの環境構築をわかりやすく解説
  2. NEO(ネオ)上でスマートコントラクトを実装してHello Worldを表示させてみよう!
  3. NEO(ネオ)上の独自トークン”NEP5”を自分で発行してみるには?
  4. NEO(ネオ)上でNEP5を使ってICOをしてみよう
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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_ardinghelli

docker 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しましょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelアプリケーションをAWS上のDockerで動かす

概要

LaravelのアプリケーションをAWS上のDockerで動かすための環境を構築します。
具体的には、以下を行います。

  1. コンテナを構築するためのDockerfileを作成する
  2. ECRリポジトリの作成 → AWS CLIで作成
  3. 1.で作成したDockerイメージをECRにをpushする
  4. ECSの環境構築 → マネジメントコンソールから作成

前提条件

  • AWS CLIがインストールがインストールされていること

コンテナを構築

phpnginxの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.ini

nginxの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 サービスと簡単に連携することができます。

Amazon ECR

事前準備

AWS CLIを使用して、ECR用のプロファイルを作成します。

$ aws configure --profile ecr

リポジトリ作成

phpeginxの2つのリポジトリを作成します。

$ aws ecr create-repository --repository-name php --profile ecr
$ aws ecr create-repository --repository-name nginx --profile ecr

マネジメントコンソールで作成する場合は、以下の通りです。

Amazon ECR > Repositoriesを選択し、リポジトリの作成をクリックします。
スクリーンショット 2019-02-26 16.07.08.png

リポジトリ名を入力し、リポジトリの作成をクリックして、リポジトリを作成します。
スクリーンショット 2019-02-26 16.08.30.png

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.2MB

ECRにログイン

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:latest

ECSの環境構築

セキュリティグループの作成

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 Service

sshログインを可能とする場合、キーペアを指定している必要があります。
この場合、セキュリティグループで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で動かす

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ECSでfluentdを使ってコンテナ毎にlogging

背景

nginx -> appという流れのコンテナを組んでいます。
nginxはawslogsドライバを使って、cloudwatchにログを流しても全然問題無いんですが、appコンテナは諸事情でそうもいかない背景があり、fluentd経由でcloudwatchにログを送りたいと考えました。

願望

  • コンテナ内でlogrotationの設定はしたくない。
  • cloudwatchのログストリーム名はコンテナ毎にユニークにしたい。
  • FluentdコンテナをECSで起動する

つくるもの

下記の図のようなものをつくります。

Untitled Diagram (1).png

やること

  • 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の設定をしています。

スクリーンショット 2019-02-28 13.23.05.png

下記のようすることでCloudwatchのログストリーム名はコンテナ毎にユニークになります。

app.{{.Name}}.{{}.ID}

FluentdコンテナをECSで起動する

起動するECSインスタンスそれぞれにfluentdコンテナはいてほしいので DAEMON で起動します。

スクリーンショット 2019-02-28 13.28.12.png

(おまけ)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>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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/fstab

3.ミドルウェアのインストール

必要なパッケージを入れていく。

$ sudo apt-get update
$ sudo apt-get install -y python3-pip unzip docker.io nginx
$ sudo pip3 install docker-compose

4.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 redis

Dockerイメージを作成する。インスタンスタイプによってはすごく時間がかかる。

$ 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.crt

nginxの設定

nginxの設定ファイルを編集する。先ほど作成したサーバ証明書と秘密鍵は
ssl_certificate,ssl_certificate_keyにパス付で指定する。

$ sudo vim /etc/nginx/sites-enabled/default

以下の内容に入れ替える。

/etc/nginx/sites-enabled/default
map $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 nginx

6.再び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.production
20 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:precompile

Mastodonのコンテナを起動する。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/tcp

Mastodonに接続する

以上で完了。ChromeかEdgeあたりのWebブラウザで接続する。
FireFoxはオレオレ証明書のサイトは見れないので他のブラウザを使う。

https://EC2インスタンスのパブリックDNS or パブリックIP/about
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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}

attachexit時、コンテナが停止する

$ docker start ${contenaName or contenaID}
$ docker stop ${contenaName or contenaID}
$ docker rm ${contenaName or contenaID}
 $ docker rmi ${imageName or imageID}

自分でイメージを作成する場合

dockerfile: buildの手順書

./dockerfile
FROM 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-compose
chmod +x /usr/local/bin/docker-compose

docker-Composeが使用できるか確認

$ docker-compose --version

Docker Composeを使ってみる

./dockerfile
FROM 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.yml
version: '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.py
from 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.txt
flask
jsonify
$ docker-compose up -d

アクセスできるかホストから確認

$ curl http://localhost:5000
  {"message":"Hello flask!"}

参考

Docker | docker build と Dockerfile でイメージをビルドする基本
Python+Flask環境をDockerで構築する
Dockerfileについて
docker-compose.ymlの命令を理解して、よりDockerを有効活用したい!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.2CE(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:行 59

PowerShellからの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/124454

Docker再起動後、問題なく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 bash

Web検索すると「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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

8年前に作った HTML5 アプリを最近の技術で作り直した話(5年ぶり2回目)

icotile は、HTML5 を活用して iTunes のような操作感で Twitter の友達やリストを管理できる Web アプリケーションです。2011年に最初のバージョンをリリースし、2014年には、AngularJS と Bootstrap で全面的に書き換えた icotile2 をリリースしました。この8年間で延べ 55,000ユーザーに利用されている Web アプリです。

icotile3 のメイン画面

随分ほったらかしにしていたのですが、いまだに意外と使われていて、たまに要望とかもいただいていました。最近プロダクトを作っていなかったので、最新の技術を勉強するために、icotile3 の開発に着手しました。

随分古い技術スタックだったのと、勉強も兼ねているので、できるだけまだ使ったことのない技術を採用してみました。また、サーバサイドの Node.js への置き換えも行って、フロントエンドとバックエンドの共通化も図ってみました。機能はほぼ同等+アルファですが、データベース以外はほぼ置き換えです。

icotile (2011) icotile2 (2014) icotile3 (2019)
Front-end
Framework
jQuery 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 をお試しください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む