20190218のdockerに関する記事は10件です。

docker hub とQiita

Qiitaにソースコードの記事を書いたらその作業をdocker hubに保存するようにしている。

当初は1記事1 docker hubにしようと思った。
類似の環境はまとめるようにしている。

name date star downloads URL
https://hub.docker.com/r/kaizenjapan/softether 18 minutes ago 0 3 softether on docker(作業中) https://qiita.com/kaizen_nagoya/items/fd8778bc768f2be734e2
https://hub.docker.com/r/kaizenjapan/cobol 5 hours ago 0 2 COBOLを40年ぶりにうごかしてみた:dockerでcobol https://qiita.com/kaizen_nagoya/items/9d9a216ce1b7b05dbb43
https://hub.docker.com/r/kaizenjapan/mccgcc 9 days ago 0 1 The Modern C++ Challenge error調査。https://qiita.com/kaizen_nagoya/items/82585dc0dfa3cc54f6cc
https://hub.docker.com/r/kaizenjapan/oneliner 13 days ago 0 1 One liner program on docker https://qiita.com/kaizen_nagoya/items/43ccf4e2d16e3a81adba
https://hub.docker.com/r/kaizenjapan/jq 14 days ago 0 1 docker で jq https://qiita.com/kaizen_nagoya/items/8b35775c354cac36093b
https://hub.docker.com/r/kaizenjapan/100pon 25 days ago 0 5 言語処理100本ノックをdockerで。https://qiita.com/kaizen_nagoya/items/7e7eb7c543e0c18438c4
https://hub.docker.com/r/kaizenjapan/gccv850src 2 months ago 0 1 64bitCPUへの道 (1)V850 gcc 64bit https://qiita.com/kaizen_nagoya/items/9934c0f9911ad29779b5
https://hub.docker.com/r/kaizenjapan/gcc2 4 months ago 0 9
https://hub.docker.com/r/kaizenjapan/anaconda2-sparkk 4 months ago 0 8 dockerで機械学習(87) with JAVA(1)「Machine Learning: End-to-End guide for Java developers」 By Richard Reese, Jennifer Reese, Bostjan Kaluza, Uday Kamath, Krishna Choppella  https://qiita.com/kaizen_nagoya/items/2d3a4f168b4c9a28b32e
https://hub.docker.com/r/kaizenjapan/r-master 4 months ago 0 21 dockerで機械学習(76) with R (6)「Mastering Machine Learning with R 」By Cory Lesmeister https://qiita.com/kaizen_nagoya/items/c3d51cdd3b811dac4d26
https://hub.docker.com/r/kaizenjapan/anaconda2-spark 4 months ago 0 7 dockerで機械学習(86) with Spark(1)「Machine Learning with Spark」 By Rajdeep Dua, Manpreet Singh Ghotra, Nick Pentreath https://qiita.com/kaizen_nagoya/items/d2fdfdf24effe5a76977
https://hub.docker.com/r/kaizenjapan/anaconda-frank 4 months ago 0 15 dockerで機械学習(40) with anaconda(40)「Hands-On Data Science and Python Machine Learning」By Frank Kane https://qiita.com/kaizen_nagoya/items/d7bc5f31d9bcffd07e82
https://hub.docker.com/r/kaizenjapan/anaconda-resheff 4 months ago 0 9 dockerで機械学習(36) with anaconda(36)「Learning TensorFlow」 By Itay Lieder, Yehezkel Resheff, Tom Hope https://qiita.com/kaizen_nagoya/items/9cd8772eea64f4d4cd06
https://hub.docker.com/r/kaizenjapan/golang 4 months ago 0 7 dockerで機械学習(85) with Go(1)「Machine Learning With Go」 By Daniel Whitenack https://qiita.com/kaizen_nagoya/items/842e83f3da652d9f3acc
https://hub.docker.com/r/kaizenjapan/scala-patrick 4 months ago 0 8 dockerで機械学習(85) with Go(1)「Machine Learning With Go」 By Daniel Whitenack https://qiita.com/kaizen_nagoya/items/842e83f3da652d9f3acc
https://hub.docker.com/r/kaizenjapan/anaconda-matthew 4 months ago 0 4
https://hub.docker.com/r/kaizenjapan/anaconda-gavin 4 months ago 0 12
https://hub.docker.com/r/kaizenjapan/ubuntu-athrill 4 months ago 0 12
https://hub.docker.com/r/kaizenjapan/anaconda-nikhil 4 months ago 0 17
https://hub.docker.com/r/kaizenjapan/anaconda-valentino 4 months ago 0 5
https://hub.docker.com/r/kaizenjapan/gcc 4 months ago 0 7
https://hub.docker.com/r/kaizenjapan/swift 4 months ago 0 6
https://hub.docker.com/r/kaizenjapan/scala-karim 4 months ago 0 9
https://hub.docker.com/r/kaizenjapan/anaconda-benjamin 4 months ago 0 4
https://hub.docker.com/r/kaizenjapan/anaconda-francois 4 months ago 0 15
https://hub.docker.com/r/kaizenjapan/anaconda2 4 months ago 0 6
https://hub.docker.com/r/kaizenjapan/anaconda3-wei 4 months ago 0 10
https://hub.docker.com/r/kaizenjapan/anaconda-douwe 4 months ago 0 6
https://hub.docker.com/r/kaizenjapan/anaconda-alice 4 months ago 0 14
https://hub.docker.com/r/kaizenjapan/r-keras 4 months ago 0 10
https://hub.docker.com/r/kaizenjapan/r-ml 4 months ago 0 17
https://hub.docker.com/r/kaizenjapan/anaconda2-willi 4 months ago 0 12
https://hub.docker.com/r/kaizenjapan/conda3-amueller 4 months ago 0 18
https://hub.docker.com/r/kaizenjapan/anaconda-sugomori 4 months ago 0 12
https://hub.docker.com/r/kaizenjapan/anaconda-handson 4 months ago 0 18
https://hub.docker.com/r/kaizenjapan/anaconda-pythonai 4 months ago 0 13
https://hub.docker.com/r/kaizenjapan/anaconda-keras 5 months ago 0 41
https://hub.docker.com/r/kaizenjapan/anaconda-deep-1 5 months ago 0 52 dockerで機械学習(12) with anaconda(12)「Deep Learning 深層学習」Ian Goodfellow, Yoshua Bengio, Aaron Courville 著 https://qiita.com/kaizen_nagoya/items/8645c9a94d8f1b1a0fd1
https://hub.docker.com/r/kaizenjapan/anaconda-keras-ten 5 months ago 0 10 dockerで機械学習(3) with anaconda(3)「直感Deep Learning」Antonio Gulli、Sujit Pal著 https://qiita.com/kaizen_nagoya/items/483ae708c71c88419c32
https://hub.docker.com/r/kaizenjapan/anaconda-deep 5 months ago 0 36 dockerで機械学習(1) with anaconda(1)「ゼロから作るDeep Learning - Pythonで学ぶディープラーニングの理論と実装」斎藤 康毅 著 https://qiita.com/kaizen_nagoya/items/a7e94ef6dca128d035ab
https://hub.docker.com/r/kaizenjapan/docker-ubuntu10-ndev 5 months ago 0 18 dockerで機械学習(105)環境構築(5)docker関連ファイルの管理 https://qiita.com/kaizen_nagoya/items/4f03df9a42c923087b5d
https://hub.docker.com/r/kaizenjapan/mrubyc 5 months ago 0 14 mruby/cをdocker hubにあげた。要点5つ課題6つ https://qiita.com/kaizen_nagoya/items/b908c594ff9d829683b5
https://hub.docker.com/r/kaizenjapan/dockertoppersssp_ssp a year ago 1 8 「名古屋のIoTは名古屋のOSで」Dockerどっかー使い方おかしかったんでしょうか。TOPPERS/SSP on RaspberryPi with Macintosh編:9つの関門 https://qiita.com/kaizen_nagoya/items/cbf40186ae4da48ec4c7
https://hub.docker.com/r/kaizenjapan/dockertoppersfmprpi64_fmp a year ago 0 30 Dockerをどっかーらどうやって使えばいいんでしょう。TOPPERS/FMP on RaspberryPi with Macintosh編 5つの関門「名古屋のIoTは名古屋のOSで」 https://qiita.com/kaizen_nagoya/items/9c46c6da8ceb64d2d7af
合計 1 534

文書履歴(document history)

ver. 0.01 初稿 20190218
ver. 0.02 URL3つ追記 20190219 午前7時
ver. 0.03 https://hub.docker.com/r/kaizenjapan に変更 20190219 午前8時
ver. 0.04 URL3つ追記 20190219 午前9時

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

Debian 10(buster) + ufw + Docker: Dockerコンテナが外部と通信できない問題の対処

いきなり対処法

update-alternatives --config iptablesで,iptables-legacyを使うよう変更する.

$ sudo update-alternatives --config iptables
alternative iptables (/usr/sbin/iptables を提供) には 2 個の選択肢があります。

  選択肢    パス                     優先度  状態
------------------------------------------------------------
* 0            /usr/sbin/iptables-nft      20        自動モード
  1            /usr/sbin/iptables-legacy   10        手動モード
  2            /usr/sbin/iptables-nft      20        手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 1
update-alternatives: /usr/sbin/iptables (iptables) を提供するためにマニュアルモードで /usr/sbin/iptables-legacy を使います

$ sudo reboot

いきなり結論

  • Debian 10はiptables v1.8系を採用.nftables APIを使うiptables-nftと旧来のiptables-legacyが用意されている.
  • デフォルトはiptables-nftだが,Dockerはiptables-legacyを使う.
  • この状態で,ufwなどを使ってiptables-nftで定義を設定すると,iptables-legacyの定義は無視される(ようだ).その結果,外部との通信ができない.
  • そこで,iptables-legacyをデフォルトに変更し,定義をlegacy側に寄せて対処する.

詳細

ufwとiptables

ufw - Uncomplicated Firewall は, ufw allow 22/tcp などと書くだけでポート開放ができる,お手軽なファイアウォール管理ツールです.

内部的には iptables(Netfilter) のラッパーのような位置づけで, iptables の忘れやすいコマンド体系を忘れたままにしておけます.もともとUbuntu向けのツールだったように思いますが,かなり前からDebianでも利用が可能です.

iptables v1.8 - nftables APIサポート

現時点で testing である Debian GNU/Linux 10 (buster) では,iptablesが1.6から1.8にバージョンアップされています.

iptables 1.8では,新たに nftables Kernel API1を用いたiptables-nftツールが提供され,旧来のツールはiptables-legacyで使用することが出来るようになっています.

iptablesはというと,Debian 10はデフォルトでiptables-nftへのシンボリックリンクが張られています.ufw等はこのデフォルトを使用します.

$ ls -l /usr/sbin/iptables
lrwxrwxrwx 1 root root 26  2月 17 11:44 /usr/sbin/iptables -> /etc/alternatives/iptables
$ ls -l /etc/alternatives/iptables
lrwxrwxrwx 1 root root 22  2月 18 22:53 /etc/alternatives/iptables -> /usr/sbin/iptables-nft

Dockerは iptables-legacy を使う

一方,Dockerはiptables-nftがうまく扱えず,デフォルトがどうあれ必ずiptables-legacyを使うように修正が加えられています2 3

ufw + Docker = iptables-nft + iptables-legacy

ここで,デフォルトのままufwとDockerを使うと,iptables-nftiptables-legacyの両方の定義が存在することになります.

$ sudo iptables-nft -L
Chain INPUT (policy DROP)
target     prot opt source               destination
ufw-before-logging-input  all  --  anywhere             anywhere
ufw-before-input  all  --  anywhere             anywhere
ufw-after-input  all  --  anywhere             anywhere
ufw-after-logging-input  all  --  anywhere             anywhere
ufw-reject-input  all  --  anywhere             anywhere
ufw-track-input  all  --  anywhere             anywhere
(省略)

$ sudo iptables-legacy -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy DROP)
target     prot opt source               destination
DOCKER-USER  all  --  anywhere             anywhere
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere
(省略)

ここから先は推測が入りますが,この状態になると iptables-nft の定義のみが有効となるようです.そのため,Dockerがせっかく書き換えてくれた定義が効かず,コンテナが外部と通信できなくなってしまいます.

pingでIPアドレスを指定すると通るが,ホスト名を指定するとDNSが引けない,という状況です.

$ sudo docker run -it --rm busybox
/ # ping github.com
ping: bad address 'github.com'
/ # ping 192.30.255.112
PING 192.30.255.112 (192.30.255.112): 56 data bytes
64 bytes from 192.30.255.112: seq=0 ttl=49 time=133.961 ms
64 bytes from 192.30.255.112: seq=1 ttl=49 time=134.677 ms

対処: iptables-legacyをデフォルトにする

さて,対処法ですが,ufwも含めてみんなiptables-legacyを使うようにします.

Docker doesn't work with iptables v1.8.1 · Issue #38099 · moby/mobyのIssue commentにもあるように,デフォルトのiptablesは選べるようになっています.そこで,iptables-legacyをデフォルトに変更します.

$ sudo update-alternatives --config iptables
alternative iptables (/usr/sbin/iptables を提供) には 2 個の選択肢があります。

  選択肢    パス                     優先度  状態
------------------------------------------------------------
* 0            /usr/sbin/iptables-nft      20        自動モード
  1            /usr/sbin/iptables-legacy   10        手動モード
  2            /usr/sbin/iptables-nft      20        手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 1
update-alternatives: /usr/sbin/iptables (iptables) を提供するためにマニュアルモードで /usr/sbin/iptables-legacy を使います

あとは再起動すれば完了です.

iptables-nftでの定義が残っていても,iptables-legacyをデフォルトとしていると,legacyが優先されるようです.

参考


  1. API自体は2014年1月にリリースされたLinux Kernel 3.13から提供されている 

  2. 本来iptables-nftでも同じコマンドで通るはずなのですが,謎.Pull requestには『トランスレータのバグかもね? 追っかけきれてないけど?』みたいなコメントが見られる. 

  3. nftablesサポートについてはかなり前からIssueが上がっている様子([feature request] nftables support · Issue #26824 · moby/moby). 

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

DockerでWebpack+Babel開発環境作ってみた

はじめに

ES6以上のJSをES5にトランスパイルするのに便利なBabelの環境を作ってみたいと思います。
vue.jsやReact.jsと組み合わせたwebpackやbabel環境構築の記事はよく見かけますが、今回はdockerでwebpack+babelのみの開発環境構築をご紹介します。

環境

以下の環境で動作確認はしております。

MacOS Mojave 10.14.3
Docker version 18.09.2
docker-compose version 1.23.2, build 1110ad01

構成

dist/にbundle.jsを作成することをゴールとします。

├── dist
│   └── bundle.js
├── docker
│   └── webpack
│       ├── Dockerfile
│       ├── package.json
│       └── webpack.config.js
├── docker-compose.yml
└── src
    ├── app.js
    └── test.js

構築

1. docker-compose.yml作成

今回は、bundle.jsを作成するためだけのコンテナを作成します。

docker-compose.yml
version: '3'

services:
  webpack:
    build: ./docker/webpack
    volumes:
      - ./src:/my_webpack/src
      - ./dist:/my_webpack/dist
      - ./docker/webpack/package.json:/my_webpack/package.json
      - ./docker/webpack/webpack.config.js:/my_webpack/webpack.config.js
    ports:
      - 2000:2000

2. Dockerfile作成

Dockerfile
FROM node:8.15.0
WORKDIR /my_webpack
RUN npm init -y
RUN npm install -D webpack webpack-cli babel-loader @babel/core @babel/preset-env
RUN npm install jquery

CMD ["npm", "run", "build"]

3. package.json作成

ファイルの変更を検知して、再ビルドしてもらうために --watch オプションをつけてます。
あと、今回はjQueryもちゃっかり入れてます。不要な人は、削除しても構いません。

package.json
{
  "scripts": {
    "build": "webpack --watch"
  },
  "dependencies": {
    "jquery": "^3.3.1"
  },
  "devDependencies": {
    "@babel/core": "7.0.0",
    "@babel/preset-env": "7.0.0",
    "babel-loader": "^8.0.0",
    "webpack": "^4.17.1",
    "webpack-cli": "^3.1.0"
  },
  "private": true
}

4. webpack.config.js

ターゲットのブラウザも指定できるので、ここで指定しちゃいます。
エントリポイントはsrc/直下に配置するapp.js、dist/以下にbundle.jsとして出力するように設定しています。

webpack.config.js
const presets  = [
  [
    '@babel/preset-env',
    {
      "targets": [">0.25% in JP", "not ie <= 10", "not op_mini all"]
    }
  ]
];
module.exports = {
  mode   : 'development',
  devtool: 'inline-source-map',
  entry  : './src/app.js',
  output : {
    path    : `${__dirname}/dist`,
    filename: 'bundle.js'
  },
  module : {
    rules: [
      {
        test: /\.js$/,
        use : [
          {
            loader : 'babel-loader',
            options: {
              presets: presets
            }
          }
        ]
      }
    ]
  }
};

5. ES6のサンプル用意

トランスパイル用のES6で書かれたサンプルを用意します。

app.js
import Test from './test';

Test.viewConsole();
test.js
export default class Test {
  static viewConsole () {
    ['cat', 'dog', 'bear'].forEach(item => {
      console.log(item);
    });
  }
}

結果

docker-composeで起動

$ docker-compose up -d

dist直下にbundle.jsが作成されて入れば成功です。
また、app.jsやtest.jsを編集してみて下さい。
それに応じて、bundle.jsも再ビルドされていることでしょう。

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

NGINX Unit+Django(WSGI) Dockerコンテナ構築

DjangoをNGINX/Unitで公開するためのDockerコンテナを作成します。

内容

  • 前記事Windows10+WSL+Docker環境を構築
  • NGINX/Unit+Djangoのコンテナを構築

カスタマイズ

NGINX/Unitとは?

公式サイトに記載の通り、(誤解を恐れず表現すると)NGINXの動的アプリサーバ版です。
WSGIに沿ってPythonスクリプトを記述することで、動的アプリを公開できます。

  • WSGIに準拠したスクリプトを直接起動できる (中間モジュールを必要としない)
  • 設定更新を動的に実施できる(ソケットに流し込む)

Djangoとは?

DjangoはPythonの代表的フルスタックフレームワークです。

用意するもの

名称 内容
Docker Dokerfile Dockerイメージのレシピ
unit.conf.json NGINX Unitの設定
entrypoint.sh コンテナ起動スクリプト
requirements.pip pip freezeの出力
.docerignore 参考サイト
コンテンツ Pythonスクリプト Djangoで作成

src/
├── Dockerfile
├── .dockerignore
├── unit.conf.json
├── entrypoint.sh
├── requirements.pip
└── xxx/ (Django)
   ├── xxx
   |   ├── wsgi.py
   |   └── etc...
   └── polls

※DjangoははじめてのDjangoあたりを参考に学習してください。
※ディレクトリツリーキレイに書きたい

Dokerfile

公式イメージDockerfileを参考にしつつ作成します。
公式はDebianでPythonバージョンも古いため、UbuntuイメージにNGINX/Unitを導入する形にします。
ENVにユーザーとパスワードを記述している点が気になる方は、適宜ARGに置き換えてください。

FROM ubuntu:cosmic
ENV UBUNTU_VER cosmic
ENV PY_VER 3.6

SHELL ["/bin/bash", "-c"]
ENV DEBCONF_NOWARNINGS yes

LABEL MAINTAINER="auther"
LABEL version="1.0"
LABEL description=""

ENV CONTENTS ./project
ENV EXPOSE_PORT 8000

ENV USER api
ENV PASSWORD pass
ENV HOME /home/${USER}
ENV PROJECT_NAME xxx
ENV PROJECT_DIR ${HOME}/${PROJECT_NAME}

# initialize
RUN : "locale setting and base package" && \
    set -o pipefail && \
    perl -p -i.bak -e 's%https?://(?!security)[^ \t]+%http://ubuntutym.u-toyama.ac.jp/ubuntu/%g' /etc/apt/sources.list && \
    apt-get -y clean && apt-get -y update && \
    apt-get -qy install \
    sudo \
    tzdata \
    ca-certificates \
    gnupg \
    curl && \
    update-locale LANG=ja_JP.UTF-8 && \
    ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    : "create user" && \
    useradd -m -s /bin/bash ${USER} && \
    gpasswd -a ${USER} sudo && \
    echo "${USER}:${PASSWORD}" | chpasswd && \
    echo "Defaults visiblepw" >> /etc/sudoers && \
    echo "${USER} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# copy project
WORKDIR ${HOME}

COPY ${CONTENTS} ${HOME}/${PROJECT_NAME}
COPY unit.conf.json ${HOME}
COPY entrypoint.sh ${HOME}
COPY requirements.pip ${HOME}

RUN set -o pipefail && \
    sed \
        -e "s#%%HOME%%#$HOME#g" \
        -e "s#%%PJ%%#$PROJECT_NAME#g" \
        -e "s#%%PORT%%#$EXPOSE_PORT#g" \
        -e "s#%%PYVER%%#$PY_VER#g" \
        ${HOME}/unit.conf.json > ${HOME}/unit-conf.json && \
    chown -R ${USER}:${USER} ${PROJECT_DIR} && \
    chown ${USER}:${USER} ${HOME}/unit.conf.json && \
    chown ${USER}:${USER} ${HOME}/entrypoint.sh && \
    chown ${USER}:${USER} ${HOME}/requirements.pip && \
    ln -sf /dev/stdout ${HOME}/unit.log && \
    chmod 774 ${HOME}/entrypoint.sh

# install Project Package
WORKDIR /root
RUN set -o pipefail && \
    : "nginx unit repogitory" && \
    curl -fsSL "https://nginx.org/keys/nginx_signing.key" | apt-key add - && \
    echo "deb https://packages.nginx.org/unit/ubuntu/ ${UBUNTU_VER} unit" > /root/unit.list && \
    echo "deb-src https://packages.nginx.org/unit/ubuntu/ ${UBUNTU_VER} unit" >> /root/unit.list && \
    cp /root/unit.list /etc/apt/sources.list.d/unit.list && \
    : "project packages" && \
    apt-get -y update && apt-get -qy install \
    unit \
    unit-python${PY_VER} \
    python3 \
    python3-pip

# pip
USER ${USER}
WORKDIR ${HOME}
RUN pip3 install -r ${HOME}/requirements.pip

# start unitd
STOPSIGNAL SIGTERM
EXPOSE ${EXPOSE_PORT}

CMD ["sh", "./entrypoint.sh"]

unit.conf.json

公式ドキュメントを参考にNGINX/Unitの設定を記述したjson形式のファイルを用意します。
"%%"で囲んでいる箇所はdockerfile内で置換しています。

{
  "listeners": {
    "*:%%PORT%%": {
      "application": "%%PJ%%"
    }
  },  
  "applications": {
    "%%PJ%%": {
      "type": "python %%PYVER%%",
      "processes": 5,
      "working_directory": "%%HOME%%/%%PJ%%/",
      "path": "%%HOME%%/%%PJ%%/",
      "module": "%%PJ%%.wsgi",
      "user": "api",
      "group": "api",
      "limits": {
          "timeout": 10,
          "requests": 1000
      }
    }
  },
  "settings": {
      "http": {
          "header_read_timeout": 10,
          "body_read_timeout": 10,
          "send_timeout": 10,
          "idle_timeout": 120,
          "max_body_size": 6291456
      }
  },
  "access_log": "%%HOME%%/access.log"
}

entrypoint.sh

コンテナ生成後に実行するシェルスクリプトです。Dockerfile末尾で実行しています。
NGINX Unitを実行する方法は他にもありますが、今回はシンプルに実行します。

#!/bin/sh

sudo unitd --control unix:./control.unit.sock --log ./unit.log
sudo curl -fsSL -X PUT -d @./unit-conf.json --unix-socket ./control.unit.sock "http://localhost/config/"
sudo tail -f ./access.log

おまけ: requirements.pip

Django==2.1.5
pytz==2018.9

ビルドとコンテナ起動

コンテナイメージのビルドをおこない、起動します。
curl等で疎通確認をおこないます。

$ docker build --no-cache ./ -t proj/api
$ docker run -d --name api -p 8080:8000 proj/api
$ curl http://localhost:8080/polls/

次の記事

ベースイメージ 用途
NGINX Unit APIサーバ
mysql MySQLサーバ ←ココ
redis Redisサーバ
まとめる docker compose
  • 上記イメージをDockerfileを記述してビルド
  • Docker Composeで取りまとめる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10+WSL(Ubuntu)+Docker LNMPサーバサイド開発環境

WSL(Windows Subsytem for Linux)とDocker Desktopでカンタンにサーバサイド開発環境の準備をします。

内容

  • WindowsにおけるLNMP(Linux+Nginx+MySQL+Python)開発環境を構築
  • 今どきはコンテナ型仮想化だ
  • だが、未だにWSLではDockerは満足に動かない
  • WSLUbuntu18.04 LTSを入れて、Docker Desktopに接続して解決する

前提

なぜWSLなのか?

WSLを使えば強力なLinux CLI環境が簡単に導入できます。
VirtualBox等のVMよりも軽く、Cygwin,MinGW等の互換レイヤーとは違ってLinuxディストリビューションを導入できる強みがあります。

なぜDockerなのか?

年代 技術
~2004年 オンプレ
2005年~ ハードウェア仮想化(Xen)
2013年~ コンテナ型仮想化(Docker-Kubernetes)

なぜDocker Desktopなのか?

WSL(Ubuntu)にDockerを入れても動作しません。
WSLが提供してないカーネルサービスを要求するためです。
WindowsでDockerを使うためにはDocker Desktopが必要です。
※2019年2月時点。WSL+Ubuntu16.04+Docker(17系)ならば動くようですが古いのでオススメしません。

Dockerのほか、NGINX Unitmemfd_create()未対応で動作しません。
参考: WSLのシステムコール実装/未実装を確認する

VirtualBox+Dockerで良くないか?

Docker Desktopは仮想Linuxマシン(MobyLinuxVM)を起動し、そのマシン内でDockerを実行します。

  • VirtualBox+Docker: 仮想マシン上のLinux CLI環境+仮想マシン上のDocker
  • WSL+Docker Desktop: WSL Linux CLI環境+仮想マシン上のDocker

CLI環境が軽いというメリットがあります。
WSLでは提供していないカーネルサービスがあるため、動作しないソフトが多くあります。そこはDockerが解決します。

Ubuntu?

  • Debian系でDockerと相性がよい
  • シェア
  • 今後必須となるAI/BCパッケージサポートの厚さ

Macでよくね?

(・ω・)

Docker Desktop

インストール

Docker公式からインストーラーをダウンロードして実行する

設定

Docker DesktopのdockerデーモンにWSLから接続できるようにし、ホスト(Windows)ドライブとの共有設定をおこなう。

タスクアイコン→Setting

タブ 設定名
General Expose deamon on tcp://localhost:2375 without TLS ON
Shared Drives 共有したいドライブレター ON
Network DNS Server Fixed

WSL+Ubuntu環境の構築

WSL(Windows Subsystem for Linux)を有効にする

  1. Powershellを管理者で起動する
  2. WSLを有効にする
> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
  1. Microsoft StoreからUbuntu18.04をインストールする (検索⇒Ubuntu)

Wslttyをインストールする

WSLの標準コンソールは色々と制約が多いため、WSL向けMinttyのWslttyを使う

  1. Wslttyをインストールする
  2. スタートメニューからConfigure WSL Shortcutsを実行する
  3. 作成したショートカットからWslttyを起動する
  4. 右クリック→settingから最低限の設定をおこなう。
タブ 項目 設定
text フォント お好みで
ロケール ja_JP
文字セット UTF-8
window スクロール行数 60000とか
UI言語 ja
terminal タイプ xterm-256color

aptの初期設定

  1. WslttyまたはUbuntuを起動する
  2. リポジトリを国内ミラーに変更する
$ sudo perl -p -i.bak -e 's%https?://(?!security)[^ \t]+%http://ubuntutym.u-toyama.ac.jp/ubuntu/%g' /etc/apt/sources.list

cat /etc/apt/sources.list | grep "^deb"

deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic main restricted
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-updates main restricted
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic universe
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-updates universe
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic multiverse
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-updates multiverse
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-backports main restricted multiverse universe
deb http://security.ubuntu.com/ubuntu/ bionic-security main restricted
deb http://security.ubuntu.com/ubuntu/ bionic-security universe
deb http://security.ubuntu.com/ubuntu/ bionic-security multiverse
  • bionicの部分はUbuntuバージョンによって適宜読み替えてください
  • securityリポジトリはデフォルトのままにしておく
  1. アップデート/アップグレード
$ sudo apt -y update
$ sudo apt -y upgrade

日本語環境

  1. 日本語/タイムゾーン設定
$ sudo apt -y install language-pack-ja
$ sudo update-locale LANG=ja_JP.UTF-8
$ sudo timedatectl set-timezone 'Asia/Tokyo'
$ sudo apt -y install manpages-ja manpages-ja-dev
  1. Ubuntu Japanese Teamリポジトリを追加する
$ wget -q https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -O- | sudo apt-key add -
$ wget -q https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -O- | sudo apt-key add -
$ sudo wget https://www.ubuntulinux.jp/sources.list.d/$(lsb_release -cs).list -O /etc/apt/sources.list.d/ubuntu-ja.list
$ sudo apt -y update
$ sudo apt -y upgrade

Docker

WSL(Ubuntu)にDockerをインストールする

Docker公式の手順通り

  1. 開発(基本)パッケージを取得する
$ sudo apt update
$ sudo apt -y install build-essential git apt-transport-https ca-certificates curl gnupg2 software-properties-common
  1. Dockerリポジトリの追加
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt update
  1. Dockerのインストール
$ sudo apt install docker-ce
  1. Docker Desktopのデーモンに接続するように設定を追加
$ echo "export DOCKER_HOST=tcp://localhost:2375" >> ~/.bashrc
$ echo 'alias docker="DOCKER_HOST=${DOCKER_HOST} docker"' >> ~/.bashrc
  1. Hello world実行
$ docker run -rm hello-world
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/

各コンテナの起動

Nginx、MySQL、おまけにRedisのコンテナを実行して相互通信できるようにします

Dockerネットワークの作成

コンテナ間を繋ぐネットワークを作成する

$ docker network create development-network
$ docker network ls

コンテナの取得と起動

コンテナを取得して起動する。
各コンテナの説明はDockerHubを参照すること

$ docker run -d --name nginx --network development-network -p 8080:80 nginx
$ docker run -d --name mysql --network development-network -e MYSQL_ROOT_PASSWORD=hoge mysql
$ docker run -d --name redis --network development-network redis
オプション
--name コンテナ名
--network コンテナネットワーク名の指定
-p ホスト側ポート:コンテナ側ポート
-d バックグラウンド実行(detach)

ホスト(Windows)ドライブをマウント

コンテナ起動の際、-vオプションを指定してホスト(Windows)ドライブをマウントできる

$ docker run -rm -v /c/project:/project ubuntu ls /project
オプション
-v マウントするホスト側パス:コンテナ側パス
  • ホスト側パスはDocker Desktopが解釈できるパスで記述する
  • WSL(Ubuntu)ディレクトリをマウントすることはできない

次の記事

ベースイメージ 用途
NGINX Unit APIサーバ
mysql MySQLサーバ
redis Redisサーバ
  • 上記イメージをDockerfileを記述してビルド
  • Docker Composeで取りまとめる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10+WSL(Ubuntu)+Docker サーバサイド開発環境

WSL(Windows Subsytem for Linux)とDocker Desktopでカンタンにサーバサイド開発環境の準備をします。

内容

  • WindowsにおけるLNMP(Linux+Nginx+MySQL+Python)開発環境を構築したい
  • 今どきはコンテナ型仮想化だ
  • だが、未だにWSLではDockerは満足に動かない
  • WSLUbuntu18.04 LTSを入れて、Docker Desktopに接続して解決する

前提

なぜWSLなのか?

WSLを使えば強力なLinux CLI環境が簡単に導入できます。
VirtualBox等のVMよりも軽く、Cygwin,MinGW等の互換レイヤーとは違ってLinuxディストリビューションを導入できる強みがあります。

なぜDockerなのか?

年代 技術
~2004年 オンプレ
2005年~ ハードウェア仮想化(Xen)
2013年~ コンテナ型仮想化(Docker-Kubernetes)

なぜDocker Desktopなのか?

WSL(Ubuntu)にDockerを入れても動作しません。
WSLが提供してないカーネルサービスを要求するためです。
WindowsでDockerを使うためにはDocker Desktopが必要です。
※2019年2月時点。WSL+Ubuntu16.04+Docker(17系)ならば動くようですが古いのでオススメしません。

Dockerのほか、NGINX Unitmemfd_create()未対応で動作しません。
参考: WSLのシステムコール実装/未実装を確認する

VirtualBox+Dockerで良くないか?

Docker Desktopは仮想Linuxマシン(MobyLinuxVM)を起動し、そのマシン内でDockerを実行します。

  • VirtualBox+Docker: 仮想マシン上のLinux CLI環境+仮想マシン上のDocker
  • WSL+Docker Desktop: WSL Linux CLI環境+仮想マシン上のDocker

CLI環境が軽いというメリットがあります。
WSLでは提供していないカーネルサービスがあるため、動作しないソフトが多くあります。そこはDockerが解決します。

Ubuntu?

  • Debian系でDockerと相性がよい
  • シェア
  • 今後必須となるAI/BCパッケージサポートの厚さ

Macでよくね?

(・ω・)

Docker Desktop

インストール

Docker公式からインストーラーをダウンロードして実行する

設定

Docker DesktopのdockerデーモンにWSLから接続できるようにし、ホスト(Windows)ドライブとの共有設定をおこなう。

タスクアイコン→Setting

タブ 設定名
General Expose deamon on tcp://localhost:2375 without TLS ON
Shared Drives 共有したいドライブレター ON
Network DNS Server Fixed

WSL+Ubuntu環境の構築

WSL(Windows Subsystem for Linux)を有効にする

  1. Powershellを管理者で起動する
  2. WSLを有効にする
> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
  1. Microsoft StoreからUbuntu18.04をインストールする (検索⇒Ubuntu)

Wslttyをインストールする

WSLの標準コンソールは色々と制約が多いため、WSL向けMinttyのWslttyを使う

  1. Wslttyをインストールする
  2. スタートメニューからConfigure WSL Shortcutsを実行する
  3. 作成したショートカットからWslttyを起動する
  4. 右クリック→settingから最低限の設定をおこなう。
タブ 項目 設定
text フォント お好みで
ロケール ja_JP
文字セット UTF-8
window スクロール行数 60000とか
UI言語 ja
terminal タイプ xterm-256color

aptの初期設定

  1. WslttyまたはUbuntuを起動する
  2. リポジトリを国内ミラーに変更する
$ sudo perl -p -i.bak -e 's%https?://(?!security)[^ \t]+%http://ubuntutym.u-toyama.ac.jp/ubuntu/%g' /etc/apt/sources.list

cat /etc/apt/sources.list | grep "^deb"

deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic main restricted
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-updates main restricted
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic universe
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-updates universe
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic multiverse
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-updates multiverse
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-backports main restricted multiverse universe
deb http://security.ubuntu.com/ubuntu/ bionic-security main restricted
deb http://security.ubuntu.com/ubuntu/ bionic-security universe
deb http://security.ubuntu.com/ubuntu/ bionic-security multiverse
  • bionicの部分はUbuntuバージョンによって適宜読み替えてください
  • securityリポジトリはデフォルトのままにしておく
  1. アップデート/アップグレード
$ sudo apt -y update
$ sudo apt -y upgrade

日本語環境

  1. 日本語/タイムゾーン設定
$ sudo apt -y install language-pack-ja
$ sudo update-locale LANG=ja_JP.UTF-8
$ sudo timedatectl set-timezone 'Asia/Tokyo'
$ sudo apt -y install manpages-ja manpages-ja-dev
  1. Ubuntu Japanese Teamリポジトリを追加する
$ wget -q https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -O- | sudo apt-key add -
$ wget -q https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -O- | sudo apt-key add -
$ sudo wget https://www.ubuntulinux.jp/sources.list.d/$(lsb_release -cs).list -O /etc/apt/sources.list.d/ubuntu-ja.list
$ sudo apt -y update
$ sudo apt -y upgrade

Docker

WSL(Ubuntu)にDockerをインストールする

Docker公式の手順通り

  1. 開発(基本)パッケージを取得する
$ sudo apt update
$ sudo apt -y install build-essential git apt-transport-https ca-certificates curl gnupg2 software-properties-common
  1. Dockerリポジトリの追加
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt update
  1. Dockerのインストール
$ sudo apt install docker-ce
  1. Docker Desktopのデーモンに接続するように設定を追加
$ echo "export DOCKER_HOST=tcp://localhost:2375" >> ~/.bashrc
$ echo 'alias docker="DOCKER_HOST=${DOCKER_HOST} docker"' >> ~/.bashrc
  1. Hello world実行
$ docker run -rm hello-world
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/

(参考) 各コンテナの起動とコンテナ間通信

Nginx、MySQL、おまけにRedisのコンテナを実行して相互通信する例です。

Dockerネットワークの作成

コンテナ間を繋ぐネットワークを作成する

$ docker network create development-network
$ docker network ls

コンテナの取得と起動

コンテナを取得して起動する。
各コンテナの説明はDockerHubを参照すること

$ docker run -d --name nginx --network development-network -p 8080:80 nginx
$ docker run -d --name mysql --network development-network -e MYSQL_ROOT_PASSWORD=hoge mysql
$ docker run -d --name redis --network development-network redis
オプション
--name コンテナ名
--network コンテナネットワーク名の指定
-p ホスト側ポート:コンテナ側ポート
-d バックグラウンド実行(detach)

Dockerネットワークを設定することで、
例えばredisコンテナからhttp://nginx:80/のような形でnginxコンテナのNGINXにコンテナ間通信できる。

(参考) ホスト(Windows)ドライブをマウント

コンテナ起動の際、-vオプションを指定してホスト(Windows)ドライブをマウントできる

$ docker run -rm -v /c/project:/project ubuntu ls /project
オプション
-v マウントするホスト側パス:コンテナ側パス
  • ホスト側パスはDocker Desktopが解釈できるパスで記述する
  • WSL(Ubuntu)ディレクトリをマウントすることはできない

次の記事

ベースイメージ 用途
NGINX Unit APIサーバ
mysql MySQLサーバ
redis Redisサーバ
  • 上記イメージをDockerfileを記述してビルド
  • Docker Composeで取りまとめる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10+WSL(Ubuntu)+Docker サーバサイド開発環境

Windows10+WSL(Ubuntu)+Docker サーバサイド開発環境

WSL(Windows Subsytem for Linux)とDocker Desktopでカンタンにサーバサイド開発環境を準備します。

内容

  • WindowsにおけるLNMP(Linux+Nginx+MySQL+Python)開発環境を構築
  • 今どきはコンテナ型仮想化だ
  • だが、未だにWSLではDockerは満足に動かない
  • WSLUbuntu18.04 LTSを入れて、Docker Desktopに接続して解決する

前提

なぜWSLなのか?

WSLを使えば強力なLinux CLI環境が簡単に導入できます。
VirtualBox等のVMよりも軽く、Cygwin,MinGW等の互換レイヤーとは違ってLinuxディストリビューションを導入できる強みがあります。

なぜDockerなのか?

年代 技術
~2004年 オンプレ
2005年~ ハードウェア仮想化(Xen)
2013年~ コンテナ型仮想化(Docker-Kubernetes)

なぜDocker Desktopなのか?

WSL(Ubuntu)にDockerを入れても動作しません。
WSLが提供してないカーネルサービスを要求するためです。
WindowsでDockerを使うためにはDocker Desktopが必要です。
※2019年2月時点。WSL+Ubuntu16.04+Docker(17系)ならば動くようですが古いのでオススメしません。

Dockerのほか、NGINX Unitmemfd_create()未対応で動作しません。
参考: WSLのシステムコール実装/未実装を確認する

VirtualBox+Dockerで良くないか?

Docker Desktopは仮想Linuxマシン(MobyLinuxVM)を起動し、そのマシン内でDockerを実行します。

  • VirtualBox+Docker: 仮想マシン上のLinux CLI環境+仮想マシン上のDocker
  • WSL+Docker Desktop: WSL Linux CLI環境+仮想マシン上のDocker

WSLはCLI環境部分が軽量です。

提供していないカーネルサービスがあるため動かないソフトもありますが、そこはDockerで解決します。

Ubuntu?

  • Debian系でDockerと相性がよい
  • シェア
  • トレンドのAI/BCパッケージサポートの厚さ

Macでよくね?

(・ω・)

Docker Desktop

インストール

Docker公式からインストーラーをダウンロードして実行する。

設定

Docker DesktopのdockerデーモンにWSLから接続できるようにし、ホスト(Windows)ドライブとの共有設定をおこなう。

タスクアイコン→Setting

タブ 設定名
General Expose deamon on tcp://localhost:2375 without TLS ON
Shared Drives 共有したいドライブレター ON
Network DNS Server Fixed

WSL+Ubuntu環境の構築

WSL(Windows Subsystem for Linux)を有効にする

  1. Powershellを管理者で起動する
  2. WSLを有効にする
> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
  1. Microsoft StoreからUbuntu18.04をインストールする (検索⇒Ubuntu)

Wslttyをインストールする

WSLの標準コンソールは色々と制約が多いため、WSL向けMinttyのWslttyを使う

  1. Wslttyをインストールする
  2. スタートメニューからConfigure WSL Shortcutsを実行する
  3. 作成したショートカットからWslttyを起動する
  4. 右クリック→settingから最低限の設定をおこなう。
タブ 項目 設定
text フォント お好みで
ロケール ja_JP
文字セット UTF-8
window スクロール行数 60000とか
UI言語 ja
terminal タイプ xterm-256color

aptの初期設定

  1. WslttyまたはUbuntuを起動する
  2. リポジトリを国内ミラーに変更する
$ sudo perl -p -i.bak -e 's%https?://(?!security)[^ \t]+%http://ubuntutym.u-toyama.ac.jp/ubuntu/%g' /etc/apt/sources.list

cat /etc/apt/sources.list | grep "^deb"

deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic main restricted
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-updates main restricted
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic universe
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-updates universe
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic multiverse
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-updates multiverse
deb http://ubuntutym.u-toyama.ac.jp/ubuntu/ bionic-backports main restricted multiverse universe
deb http://security.ubuntu.com/ubuntu/ bionic-security main restricted
deb http://security.ubuntu.com/ubuntu/ bionic-security universe
deb http://security.ubuntu.com/ubuntu/ bionic-security multiverse
  • bionicの部分はUbuntuバージョンによって適宜読み替えてください
  • securityリポジトリはデフォルトのままにしておく
  1. アップデート/アップグレード
$ sudo apt -y update
$ sudo apt -y upgrade

日本語環境

  1. 日本語/タイムゾーン設定
$ sudo apt -y install language-pack-ja
$ sudo update-locale LANG=ja_JP.UTF-8
$ sudo timedatectl set-timezone 'Asia/Tokyo'
$ sudo apt -y install manpages-ja manpages-ja-dev
  1. Ubuntu Japanese Teamリポジトリを追加する
$ wget -q https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -O- | sudo apt-key add -
$ wget -q https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -O- | sudo apt-key add -
$ sudo wget https://www.ubuntulinux.jp/sources.list.d/$(lsb_release -cs).list -O /etc/apt/sources.list.d/ubuntu-ja.list
$ sudo apt -y update
$ sudo apt -y upgrade

Docker

WSL(Ubuntu)にDockerをインストールする

Docker公式の手順通り

  1. 開発(基本)パッケージを取得する
$ sudo apt update
$ sudo apt -y install build-essential git apt-transport-https ca-certificates curl gnupg2 software-properties-common
  1. Dockerリポジトリの追加
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt update
  1. Dockerのインストール
$ sudo apt install docker-ce
  1. Docker Desktopのデーモンに接続するように設定を追加
$ echo "export DOCKER_HOST=tcp://localhost:2375" >> ~/.bashrc
$ echo 'alias docker="DOCKER_HOST=${DOCKER_HOST} docker"' >> ~/.bashrc
  1. Hello world コンテナを実行
$ docker run -rm hello-world
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/

次回

ベースイメージ 用途
NGINX Unit APIサーバ
mysql MySQLサーバ
redis Redisサーバ
  • 上記イメージをDockerfileを記述してビルド
  • Docker Composeで取りまとめる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker Containerの終了時にExit Code 137 (SIGKILL)が出る時の対処法

概要

これの日本語版のようなもの

問題

複数のコマンドを扱うDockerを使うとき、こんな感じのスクリプトになりませんか?

run.sh

#!/bin/sh -e

pip install --upgrade poetry
poetry config settings.virtualenvs.create false
poetry install
python ./manage.py runserver 0.0.0.0:8000

backend.dockerfile

from python:3.6
env PYTHONUNBUFFERED 1
run mkdir /code
workdir /code

docker-compose.yml

version: '3'

services:
  db:
    image: postgres:alpine
    environment:
      POSTGRES_PASSWORD: fingine
      POSTGRES_USER: fingine
      POSTGRES_DB: fingine
  backend:
    build:
      context: ./docker
      dockerfile: backend.dockerfile
    command: bash -c ./run.sh
    stop_signal: SIGINT
    env_file: ./docker/dev.env
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

これ、docker-compose upした後にdocker-compose stopすると、fingine_backend_1 exited with code 137と、エラーコード137、つまりSIGKILLが返された上で終了する。つまり、終了まで10秒ほど待たされる上に強制終了を食らう

で、調べるとやれ、メモリが足りないだのtrapコマンドを仕掛けろだのと的外れな回答ばかりで嫌気が差した。だから書いてやった。

解決法

注目すべき点はexecビルトインユーティリティコマンドにあります。通常、shell芸で書かれたコマンドは新しいプロセスを生成してそこでコマンドを実行します。この新しく生成されたプロセスでは、後述する問題によってシグナルを受信することができません。

しかし、execにコマンドライン引数としてコマンドとその引数を指定すると、コマンドのプロセスを生成せずに、シェルのプロセスとそのコマンドのプロセスを置き換えます。つまり、先程のrun.shを次のように書き換えると解決するのでは・・・と考えますよね?

run.sh

#!/bin/sh -e

pip install --upgrade poetry
poetry config settings.virtualenvs.create false
poetry install
exec python ./manage.py runserver 0.0.0.0:8000  # <-- これ。

実はこれだと不十分っす。 というのも、Dockerの終了シグナルはコンテナ内のプロセスIDが1のプロセスに対してのみ発火します。さあ、docker-compose.ymlを見てみましょう。

docker-compose.yml

version: '3'

services:
  db:
    image: postgres:alpine
    environment:
      POSTGRES_PASSWORD: fingine
      POSTGRES_USER: fingine
      POSTGRES_DB: fingine
  backend:
    build:
      context: ./docker
      dockerfile: backend.dockerfile
    command: bash -c ./run.sh  # <-- これ
    stop_signal: SIGINT
    env_file: ./docker/dev.env
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

要するに、bashコマンドをrun.shを引数にとって実行している、つまり、run.shの実行には新しいプロセスが生成される、と。 そういうことですね。

というわけで、このdocker-compose.ymlに記述されているrun.shの呼び出しをbashではなく、execを使って呼び出されるようにする必要があります。

幸いなことに、dockerには手軽にexecを使ったコマンドを記述する方法があり、今回はこれを用いることにします。

docker-compose.yml

version: '3'

services:
  db:
    image: postgres:alpine
    environment:
      POSTGRES_PASSWORD: fingine
      POSTGRES_USER: fingine
      POSTGRES_DB: fingine
  backend:
    build:
      context: ./docker
      dockerfile: backend.dockerfile
    command: ['./run.sh'] # <-- これ。配列として書き直すとexecに続くコマンドとして認識される。
    stop_signal: SIGINT
    env_file: ./docker/dev.env
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

さあこれでdocker-compose upしてdocker-compose stopしてみましょう。コンテナを10秒も待つことなく、fingine_backend_1 exited with code 0、つまりコード0、正常終了させる事ができます。素晴らしい!!

最後に

Schlawackさんの記事によって筆者のdockerの問題が解決した事に謝辞を申し上げます。

参考記事

Hynek Schlawack, Why Your Dockerized Application Isn’t Receiving Signals, 19 June 2017

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

Amazon ECS+Fargate入門 (terraformを使ったクラスタ構築とオートスケール、ブルーグリーンデプロイ)

はじめに

コンテナベースでインフラ実現するに伴って色々AWS上でのコンテナ周り調べたり、本番導入した際のまとめ的なメモです。
大雑把にこんなことを書いてます。

  • 構成概念と基礎知識
  • terraformによるコードデプロイ連携でのブルーグリーンデプロイ
  • terraformによるメトリクスベースでのオートスケーリング

ECS+Fargateのインフラアーキテクチャ全体像

image.png
* AWS公式からの引用

ECSとは

ECSはAWSが提供するk8sと同じようなクラスタ構成でのコンテナオケーストレーション
を実現するサービス。
ECSは実際にコンテナが稼働する複数のworkerNodeとその操作・管理を担当するmasterNodeの
クラスタ構造を採用する事で分散・冗長化・スケーラブルなインフラを構築できる。
具体的には以下のような機能を提供をしている。

  • クラスタの管理(workerNodeへの自動参加・死活監視や操作など)
  • クラスタ上でのコンテナのデプロイメント(ノードに対する配置戦略・生成・ローリングアップデート)
  • コンテナ群のスケールイン/アウト
  • 外部サービス公開用のインタフェースの定義と動作するコンテナとロードバランサとの紐付けといったような外部との接合)
  • コンテナに対するヘルスチェック機能(成否に伴なった外部アクセスに対するアタッチ・デタッチやコンテナ自体に不備発生した場合の再起動)
  • スケジュールジョブ

Fargateとは

ECSクラスタのワーカーノードにあたる部分は自分でecsエージェントを起動させたEC2のオートスケーリンググループを組み、
リソース管理やスケールインアウトを操作する必要があった。
ECS Fargateはワーカー部分も含めて、フルマネージドで実現しているので
Fargateを採用する事で実際にコンテナを起動させていたEC2の管理や
スケールイン/アウト/アップに伴うクラスタ自身のリソース管理や作成から解放される。

AWSではEKSというkubernetesを採用したコンテナオーケストレーションサービスもあるのだけど、
こちらは現時点(2019/01)ではFargate未対応でEKS最適化されたamiイメージを元に
EC2でWorkerNodeを構成することになる。

サポートするVCPUとMemoryの組み合わせはこちら

Fargateの制約やデメリット

大雑把に。

  • awsvpcモード必須

  • logDriverがawslogsに限定される

cloudwatchとの連携は用意だがそれ以外のログの収集や送信(たとえばfluentdなど)との複数コンテナ稼働時のログ収集においては一工夫しないといけなかったり。

  • 共有ボリュームは~4GB

概ねサイドカーエージェントでログ転送とかする際の置き場になる気がするんだけど、上限が低いので
ローテートとかちゃんと組まないと枯渇する

  • kill時の設定が素のECSよかいじれなかったり

  • デプロイと起動が素のECSより少し遅い。

  • EC2と同スペック比較すると15~20%くらいは高くなる。

この辺はtask定義のパラメータにも記載があるので

また起動数などのサービス制約もあるので、緩和申請なども場合によっては必要

ECSを構成する要素

image.png
(AWS公式のチュートリアルからの引用

  • Cluster
  • Service
  • Container Definition
  • Task & TaskDefinition

によってECSは構成されている。
次項で項目別に記載していく。
実際にはTaskDefinition中にContainerDefinitionは内包されている。

Cluster

ServiceやTaskが所属する論理的なグルーピング。
FargateでなくEC2起動タイプを選択している場合は所属するクラスタのworkerNodeであるEC2インスタンスを共有する。

Task & TaskDefinition

Task

TaskDefinitionの定義を実行に移している実行されている複数のコンテナを指す。
例えばgoとnginxを組み合わせて動いているようなwebアプリケーションを二つのコンテナ構成で動作させる場合は
以下のようなコンテナの組み合わせが1Taskとして扱われる。

* sample_go_application_task
  - nginx
  - go

TaskDefinition

Taskの定義というと(まんま)
アプリケーションをどのようにコンテナを組み合わせるか、リソースをどれくらい許容するか、
IAMやネットワークはどのようにするか、というようなコンテナの動作に必要な情報を設定する。
具体的には以下のような情報を定義する。
すごく大雑把にいうと、docker-composeにawsインフラの情報や定義が足されたようなイメージ。

  • コンテナを動かすのに必要な情報(DockerImage,Port,protocolなど)
  • 動かしたいコンテナの組み合わせ
  • コンテナ起動時の実行コマンドやdocker関連のパラメーター設定
  • 適用するIAMロールやセキュリティグループ
  • ネットワークモードや動作させるネットワーク情報
  • 使用するリソース量(CPU/メモリ)

ざっくりとした例

{
        "family": "sample",
        "networkMode": "awsvpc",
        "containerDefinitions": [
            {
                "name": "nginx",
                "image": "nginx:latest",
                "essential": true,
                "dockerLabels": {"role:nginx"}
            }, {
                "name": "go-app",
                "image": "your-go-app:latest",
                "essential": true,
                "environment": [
                    {
                        "name": "ENV_1",
                        "value": "hoge"
                    },
                    {
                        "name": "ENV_2",
                        "value": "fuga"
                    }
                ]
           }
        ],
        "requiresCompatibilities": [
            "FARGATE"
        ],
        "cpu": "256",
        "memory": "512"
}

動かすだけなら簡単に動きますが、例えばweb serverとして動作させる場合はulimitの値を設定しておかないと
ファイルディスクリプタが枯渇して爆死したりとか、memoryReservationを全く指定しないでハードリミット超えてコンテナがご臨終したりするので、パラメーターセットは公式を一度しっかり見て把握した方が良いと思います。

  • 作成
aws ecs register-task-definition --cli-input-json file://$PWD/task-definitions.json

更新はfamilyが存在していれば同一コマンドで行われて、バージョン値が自動でincrementされる。

Service

TaskDefinitionを束ねて外部にどのように公開するか、オートスケールを
どのような閾値で行うか、起動タイプ(EC2/Fargate)などの設定を記載できる。
例えばロードバランサへのtargetGroup追加したりなど。

  • aws cliから雛形をダウンロード
aws ecs create-service --generate-cli-skeleton > service.json
  • service生成
aws ecs create-service --cli-input-json file://$PWD/service.json

更新はupdate-serviceで行う。
全ての項目が更新可能ではなく作成時にしか変更できない項目もあり、項目数が多いので、詳細な説明は公式を確認した方が良いです。

例としてはこんな感じ

{
    "cluster": "test-ecs-cluster",
    "serviceName": "test-service",
    "taskDefinition": "test:30",
    "loadBalancers": [
        {
            "targetGroupArn": "loadbarancerArn",
            "containerName": "test-nginx",
            "containerPort": 80
        }
    ],
    "desiredCount": 2,
    "clientToken": "",
    "launchType": "FARGATE",
    "platformVersion": "LATEST",
    "deploymentConfiguration": {
        "maximumPercent": 200,
        "minimumHealthyPercent": 100
    },
    "networkConfiguration": {
        "awsvpcConfiguration": {
            "subnets": [
                "subnet-xxxxx",
                "subnet-xxxxx"
            ],
            "securityGroups": [
                "sg-xxxxx",
            ],
            "assignPublicIp": "DISABLED"
        }
    },
    "healthCheckGracePeriodSeconds": 0,
    "schedulingStrategy": "REPLICA",
    "deploymentController": {
        "type": "CODE_DEPLOY"
    },
    "propagateTags": "TASK_DEFINITION",
    "tags": [
        {
            "key": "env",
            "value": "stage"
        },
        {
            "key": "region",
            "value": "jp"
        }
    ],
    "enableECSManagedTags": false
}

fargate利用の場合、alb/nlbのどちらかが必須であることと、TargetGroupのtarget_typeをipで作る必要がある。

Blue/Green Deploymentしてみよう。

同じAWSのコンポーネントであるCodeDeployと連携させると結構簡単にロードバランサー振替ベースでの
Blue/Green Deploymentを実現できる。

GUIでは指示に従っていけば概ね簡単に作れるので、割愛。
CUIとterraformを使っての説明。
VPC,subnet,securityGroupは説明を省くので、よしなに作ってください。

クラスタ作成

resource "aws_ecs_cluster" "ecs_cluster" {
  name = "test-nginx-cluster"
}

resource "aws_cloudwatch_log_group" "ecs_log_group" {
  name = "/ecs/test-nginx"
  tags {
    hoge = "hoge"
    fuga = "fuga"
  }
}

ロードバランサ作成

手元で作ったのがNLBだったので、今回はNLBで。
ALBでもほぼ変わりません。

resource "aws_lb" "lb" {
  name     = "test-nginx-lb"
  internal = false

  subnets = [
    "your_subnetid",
    "your_subnetid",
  ]
  load_balancer_type = "network"
  enable_http2       = false
}

## Target Group
resource "aws_lb_target_group" "lb_target_blue" {
  name        = "blue-nlb-tg"
  port        = 80
  protocol    = "TCP"
  vpc_id      = "your_vpc_id"
  target_type = "ip"

  health_check {
    interval            = 10
    healthy_threshold   = 3
    unhealthy_threshold = 3
    protocol            = "TCP"
    port                = "traffic-port"
  }
}

## Target Group
resource "aws_lb_target_group" "lb_target_green" {
  name        = "green-nlb-tg"
  port        = 80
  protocol    = "TCP"
  vpc_id      = "your_vpc_id"
  target_type = "ip"

  health_check {
    interval            = 10
    healthy_threshold   = 3
    unhealthy_threshold = 3
    protocol            = "TCP"
    port                = "traffic-port"
  }
}

## Listeners
resource "aws_lb_listener" "lb_listner" {
  load_balancer_arn = "${aws_lb.lb.arn}"
  port              = 8081
  protocol          = "TCP"

  # blueとgreenのtgを動的に入れ替えるのでignoreする
  lifecycle {
    ignore_changes = ["default_action"]
  }

  default_action {
    target_group_arn = "${aws_lb_target_group.lb_target_blue.arn}" #初回はblueにattach
    type             = "forward"
  }
}

IAM設定

クラスタ初回作成時に自動的でecsTaskExecutionRoleAWSServiceRoleForECSが作成されます。
ECS運用時のどちらも必要になりますので、なければとりあえず手動でコンソールからぽちぽちと
クラスタ作っておくと吉。

task定義作成

terraformでもできますが、特段terraformで扱うメリットもない気がするので
ここではaws公式に沿ってjsonで。

{
    "family": "test",
    "executionRoleArn": "arn:aws:iam::xxxxxxxx:role/ecsTaskExecutionRole",
    "networkMode": "awsvpc",
    "containerDefinitions": [
        {
            "name": "test-nginx",
            "image": "nginx:latest",
            "ulimits": [
                {
                    "name": "nofile",
                    "softLimit": 65536,
                    "hardLimit": 65536
                }
            ],
            "entryPoint": [
                "sh",
                 "-c"
            ],
            "portMappings": [
                {
                    "hostPort": 80,
                    "protocol": "tcp",
                    "containerPort": 80
                }
            ],
            "command": [
                "echo blue > /usr/share/nginx/html/index.html | /usr/sbin/nginx -g \"daemon off;\""
            ],
            "memoryReservation": 256,
            "essential": true,
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "/ecs/test-nginx",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "test-nginx"
                }
            }
        }
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "512",
    "memory": "4096",
}

service作成

resource "aws_ecs_service" "ecs" {
  name                               = "test-nginx"
  cluster                            = "${aws_ecs_cluster.ecs_cluster.id}"
  task_definition                    = "test-nginx:1"
  desired_count                      = 2
  launch_type                        = "FARGATE"
  deployment_minimum_healthy_percent = 100
  deployment_maximum_percent         = 200

  network_configuration {
    subnets = [
      "your_subnet_ids"
    ]

    security_groups = [
      "yours_secuiry_groups",
    ]

    assign_public_ip = "false"
  }

  health_check_grace_period_seconds = 0

  load_balancer {
    target_group_arn = "${aws_lb_target_group.lb_target_blue.arn}"
    container_name   = "test-nginx"
    container_port   = 80
  }

  scheduling_strategy = "REPLICA"

  deployment_controller {
    type = "CODE_DEPLOY"
  }
  // deployやautoscaleで動的に変化する値を差分だしたくないので無視する
  lifecycle {
    ignore_changes = [
      "desired_count",
      "task_definition",
      "load_balancer",
    ]
  }
  propagate_tags = "TASK_DEFINITION"
}

コードデプロイアプリケーションとデプロイグループの作成

  • iamを付与
resource "aws_iam_role" "codedeploy" {
  name               = "codedeploy"
}

## ECS CodedeployPolicy

resource "aws_iam_role_policy_attachment" "ecs_deploy" {
  role       = "${aws_iam_role.codedeploy.id}"
  policy_arn = "arn:aws:iam::aws:policy/AWSCodeDeployRoleForECS"
}

## Codedeploy IAM Role Policy
data "aws_iam_policy_document" "codedeploy_iam_role_policy" {
  statement {
    actions = [
      "autoscaling:CompleteLifecycleAction",
      "autoscaling:DeleteLifecycleHook",
      "autoscaling:DescribeAutoScalingGroups",
      "autoscaling:DescribeLifecycleHooks",
      "autoscaling:PutLifecycleHook",
      "autoscaling:RecordLifecycleActionHeartbeat",
      "ec2:DescribeInstances",
      "ec2:DescribeInstanceStatus",
      "sns:*",
      "tag:GetTags",
      "tag:GetResources",
    ]

    effect    = "Allow"
    resources = ["*"]
  }
}

コードデプロイはこんな感じにリソースを作成する

resource "aws_codedeploy_app" "app" {
  compute_platform = "ECS"
  name             = "test-ecs"
}

resource "aws_codedeploy_deployment_group" "group" {
  app_name               = "test-bg-deploy"
  deployment_group_name  = "test-bg-deploy-dg"
  service_role_arn       = "${aws_iam_role.codedeploy.arn}"
  deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"

  auto_rollback_configuration {
    enabled = true
    events  = ["DEPLOYMENT_FAILURE"]
  }

  blue_green_deployment_config {
    deployment_ready_option {
      action_on_timeout = "CONTINUE_DEPLOYMENT"
    }

    terminate_blue_instances_on_deployment_success {
      action                           = "TERMINATE"
      termination_wait_time_in_minutes = "10" # デプロイ成功後の環境保持時間
    }
  }

  deployment_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  ecs_service {
    cluster_name = "your_ecs_cluster_name"
    service_name = "your_ecs_service_name"
  }

  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route {
        listener_arns = ["${aws_lb_listener.lb_listner.arn}"]
      }

      target_group {
        name = "${aws_lb_target_group.lb_target_blue.name}"
      }

      target_group {
        name = "${aws_lb_target_group.lb_target_green.name}"
      }
    }
  }
}

ブルーグリーン関連で設定できる内容として

  • 新環境にテストポートのみ振り当てて公開する
  • 新環境の保持期間
  • 環境振替を手動で行う or 時間指定

などが設定できるので、細かくは公式

デプロイしてみる

このへんはECSのコンソール上から手動なりお好みで。
吐き出してるhtmlをblue,greenで切り替えつつ、while loopなどでcurlで叩き続けると
blue/greenの切り替わりが観察できます。

fargateTaskをオートスケーリングしたい

オートスケールはGUI上でサービス作成をする際は画面上から一貫して作れますが
実際には別リソースなので、terraformで作成する際は、appautoscaling_targetを使います。
ここではCloudWatchAlarmと連携してCPUメトリクスでスケールイン/アウトするサンプルを。

resource "aws_appautoscaling_target" "test_ecs_target" {
  service_namespace  = "ecs"
  resource_id        = "service/your_cluster_name/service_name"
  scalable_dimension = "ecs:service:DesiredCount"
  role_arn           = "${data.aws_iam_role.ecs_service_autoscaling.arn}"
  min_capacity       = 2
  max_capacity       = 12
}

# Automatically scale capacity up by one
resource "aws_appautoscaling_policy" "test_scale_up" {
  name               = "scale_up"
  service_namespace  = "ecs"
  resource_id        = "service/your_cluster_name/service_name"
  scalable_dimension = "ecs:service:DesiredCount"

  step_scaling_policy_configuration {
    adjustment_type         = "ChangeInCapacity"
    cooldown                = 600
    metric_aggregation_type = "Average"

    step_adjustment {
      metric_interval_lower_bound = 0
      scaling_adjustment          = 1
    }
  }

  depends_on = ["aws_appautoscaling_target.test_ecs_target"]
}

# Automatically scale capacity down by one
resource "aws_appautoscaling_policy" "test_scale_down" {
  name               = "scale_down"
  service_namespace  = "ecs"
  resource_id        = "service/your_cluster_name/service_name"
  scalable_dimension = "ecs:service:DesiredCount"

  step_scaling_policy_configuration {
    adjustment_type         = "ChangeInCapacity"
    cooldown                = 600
    metric_aggregation_type = "Average"

    step_adjustment {
      metric_interval_lower_bound = 0
      scaling_adjustment          = -1
    }
  }

  depends_on = ["aws_appautoscaling_target.test_ecs_target"]
}

# Cloudwatch alarm that triggers the autoscaling up policy
resource "aws_cloudwatch_metric_alarm" "test_cpu_high" {
  alarm_name          = "cpu_utilization_high"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = "2"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/ECS"
  period              = "60"
  statistic           = "Average"
  threshold           = "60"

  dimensions {
    ClusterName = "your_ecs_cluster_name"
    ServiceName = "your_ecs_service_name"
  }

  alarm_actions = ["${aws_appautoscaling_policy.test_scale_up.arn}"]
}

# Cloudwatch alarm that triggers the autoscaling down policy
resource "aws_cloudwatch_metric_alarm" "test_cpu_low" {
  alarm_name          = "cpu_utilization_low"
  comparison_operator = "LessThanOrEqualToThreshold"
  evaluation_periods  = "2"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/ECS"
  period              = "60"
  statistic           = "Average"
  threshold           = "30"

  dimensions {
    ClusterName = "your_ecs_cluster_name"
    ServiceName = "your_ecs_service_name"
  }

  alarm_actions = ["${aws_appautoscaling_policy.test_scale_down.arn}"]
}

data "aws_iam_role" "ecs_service_autoscaling" {
  name = "AWSServiceRoleForApplicationAutoScaling_ECSService" 
}

参考

ecs tutorial
awsBlog ecs blue-green-deployments

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

PHP未経験者が勉強用にDockerで開発環境作ってみた

やりたいこと

できるだけ自分のPCを汚さずにいわゆるLAMP環境
(Linux, Apache, MySQL, PHP)の開発環境を手軽に構築したい。

Macの場合はMAMPやVirtualBoxがあるけど汚れちゃうし・・・

そうだ、Dockerの勉強も兼ねてDockerを使おう!!!

成果物

Dockerを使用してApache, PHP, MySQL, phpMyAdminを連携し、
PHPとMySQLの勉強に注力するための開発環境を作成しました。

https://github.com/MasanoriIwakura/php_study

開発環境

ツール名 バージョン
OS macOS Mojava 10.14.3
Docker Docker for Mac 18.06.1-ce
Docker Compose 1.22.0
PHP 7.2.7-apache (Apacheと連携されているコンテナ)
MySQL 8
phpMyAdmin 4.7

プロジェクト構成

[PHP]

Dockerコンテナの80番ポートと、ホストOSの80番ポートを紐付け。

MySQLとの接続にはmysqliを使用。
Docker ComposeだけではPHPの拡張機能をインストール出来ないため、Dockerfileで対応。

[MySQL]

Version8からデフォルトの認証方式がcaching_sha2_passwordとなっているため、
mysql_native_passwordに変更する。

この設定を行わないとMySQLに接続出来ない。

使用手順

[前提条件]

  • Dockerがインストールされていること、起動されていること
  • Docker Composeがインストールされていること

Dockerを導入していない場合、Macの場合は以下のコマンドで導入してください。

# Homebrewがインストールされていること
$ brew install docker
$ brew cask install docker
$ brew install docker-compose
# Clone
$ git clone https://github.com/MasanoriIwakura/php_study.git

# フォルダ移動
$ cd php_study

# コンテナ実行
$ docker-compose up -d

# 全てのコンテナが立ち上がっていることを確認
$ docker-compose ps
         Name                       Command               State               Ports
------------------------------------------------------------------------------------------------
php_study_mysql_1        docker-entrypoint.sh mysqld      Up      3306/tcp, 33060/tcp
php_study_php_1          docker-php-entrypoint apac ...   Up      0.0.0.0:80->80/tcp
php_study_phpmyadmin_1   /run.sh phpmyadmin               Up      0.0.0.0:8080->80/tcp, 9000/tcp

[接続確認]

PHPの表示確認は
http://localhost
にアクセス
スクリーンショット 2019-02-17 23.46.32.png

phpMyAdminの表示は
http://localhost:8080
にアクセス

スクリーンショット 2019-02-17 23.45.01.png

[ソース編集方法]

php/html直下にフォルダやphpファイルを作成・編集するだけ。

例えば、php/html/index.phpを編集した場合はhttp://localhostにアクセス、
php/html/sample/sample.phpを編集した場合はhttp://localhost/sample/sample.phpにアクセスすることで動作確認が行えます。

また、ソースを修正して保存し、ブラウザをリロードするだけで反映できるので
Dockerでイメージのリビルドや再展開は不要です。

その他

[MySQLの初期化]

起動時にmysql/sql内に実行したSQLを配置することで自動的にMySQL内にテーブルを作成したり、初期データを投入することができます。

[今回作成したDockerコンテナの再構築]

実は今回のリポジトリ直下にShellを配置しています。
実行することで永続化したファイルの削除、コンテナ削除、コンテナ再構築をいっぺんに行います。
永続化したファイルを削除したくない場合は手動でコンテナを削除してください。

# リポジトリ直下で使用
./docker-clean.sh

# 永続化したファイルを削除したくない場合(コンテナだけ削除)
docker-compose stop
docker-compose rm

今後もっと便利にすることができればこちらの記事も更新します。

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