20200305のdockerに関する記事は7件です。

dockerでpythonを使う

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

laradockで作成したプロジェクトがgithubで開けない

こちらの記事を参考に環境構築
LaradockをWindows 10 Homeにインストール

デイレクトリ構成はこんな感じ

laradockpjt/
├app(laravelのプロジェクト)
├laradock

ローカルでの環境構築を終えてgithubにpush

しかしlaradockpjt直下のappフォルダが開けない(非活性?になってる)

原因

最初にlaradockをsubmoduleとしてクローンしてない
(gitのサブモジュール機能に関して全くの無知だった…)

git clone -b LaraDock-ToolBox https://github.com/LaraDock/laradock.git
//こっちだと開けない
git submodule add https://github.com/LaraDock/laradock.git
//こっちのコマンドでlaradockをサブモジュール化

後は手順通りに進めるとOK!

すでに環境構築済みだったので巻き戻しにかなり時間食ってしまった…

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

Docker② DockerでLaravel環境構築

Dockerを使ったLaravel開発環境構築

目次

  1. 環境準備
  2. ディレクトリ作成
  3. docker-compose.yml作成
  4. Dockerfile作成
  5. PHP設定ファイル作成
  6. Nginx設定ファイル作成
  7. Laravelプロジェクト作成
  8. 動作確認

参考

Dockerを使ってLaravel開発環境構築

環境準備

どうせなので、まっさらのEC2でやってみた方が良いかなと。
最低限何が必要なんだ?ってことで前回のおさらいをしてみたけど、こんな感じか。

Dockerインストール
# sudo amazon-linux-extras install docker

Dockerサービス起動
# systemctl start docker.service

サービスの起動確認
# systemctl status docker

Dockerの自動起動設定
# systemctl enable docker

試しにDockerコマンド実行
# docker info
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 version 1.21.2, build a133471

これで大丈夫そうだった。余裕っすね。

ディレクトリ作成

以下の構成を想定しています。
project
├ docker-compose.yml
docker
│  ├ php
│  │  ├ php.ini
│  │  └ Dockerfile
│  └ nginx
│    └ default.conf
server

とのこと。(太字はディレクトリ)

# cd /var
# mkdir project
# mkdir project/docker project/server
# mkdir project/docker/{php,nginx}
# ll -d `find ./project`
drwxr-xr-x 4 root root 34 Mar  5 02:51 ./project
drwxr-xr-x 4 root root 30 Mar  5 02:52 ./project/docker
drwxr-xr-x 2 root root  6 Mar  5 02:52 ./project/docker/nginx
drwxr-xr-x 2 root root  6 Mar  5 02:52 ./project/docker/php
drwxr-xr-x 2 root root  6 Mar  5 02:51 ./project/server

別にvarじゃなくてもいいけど、なんとなくvarで。

docker-compose.yml作成

docker-composer.yml
version: '3'

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
    - ./server:/var/www

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 80:80
    volumes:
    - ./server:/var/www
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:5.7
    container_name: db-host
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 3306:3306

こんな感じにするらしい。
中身について考えてみる。

php

 php:
   container_name: php  ①
   build: ./docker/php  ②
   volumes:
   - ./server:/var/www  ③

① コンテナの名前
② ./docker/phpにあるDockerfileを参照する
③ ホスト側の./serverと、コンテナ側の/var/wwwをマウント

nginx

nginx:
  image: nginx  ①
  container_name: nginx  ②
  ports:
  - 80:80 ③
  volumes:
  - ./server:/var/www ④
  - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf ⑤
  depends_on:
  - php ⑥

① Dockerイメージの指定
② コンテナの名前
③ PORTを指定
④ ホスト側の./serverと、コンテナ側の/var/wwwをマウント
⑤ ホスト側のdefault.confを、コンテナ側にコピー(マウント?)
⑥ 依存関係を指定。この場合、nginxを実行する前にphpw実行する。

db

db:
  image: mysql:5.7 ①
  container_name: db-host ②
  environment:
    MYSQL_ROOT_PASSWORD: root ③
    MYSQL_DATABASE: database ④
    MYSQL_USER: docker ⑤
    MYSQL_PASSWORD: docker ⑥
    TZ: 'Asia/Tokyo' ⑦
  command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci ⑧
  volumes:
  - ./docker/db/data:/var/lib/mysql ⑨
  - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf ⑩
  - ./docker/db/sql:/docker-entrypoint-initdb.d ⑪
  ports:
  - 3306:3306 ⑫

DBに関しては、実際はRDSを使用したい。
現時点ではとりあえずコンテナを作成して使用する。

① Dockerイメージの指定
② コンテナの名前
③~⑦
  諸々の環境変数。
  別ファイルに記載して「env_file: .env」みたいに指定することも可能。
  (というかセキュリティ面とか考えたらその方が良いのでは)
⑧ デフォルトのコマンドを上書きする、らしい。
⑨~⑪
  諸々のマウント 
⑫ PORTを指定

Dockerfile作成

phpコンテナの構築時に、以下のDockerfileを使用する。

Dockerfile
FROM php:7.2-fpm
COPY php.ini /usr/local/etc/php/

RUN apt-get update \
  && apt-get install -y zlib1g-dev mariadb-client \
  && docker-php-ext-install zip pdo_mysql

#Composer install
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin


WORKDIR /var/www

RUN composer global require "laravel/installer"

各行の処理については、Dockerfileリファレンスを参照。

php.ini作成

phpの設定ファイル。

php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

default.conf作成

nginxの設定ファイル。

default.conf
server {
  listen 80;
    index index.php index.html;
    root /var/www/public;

  location / {
    root /var/www/public;
    index  index.html index.php;
    }

  location ~ \.php$ {

    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
 }

Laravelプロジェクト作成

docker起動
# docker-compose up -d
ERROR: Service 'php' failed to build: The command '/bin/sh -c php composer-setup.php' returned a non-zero code: 1

こけた。
こけたら元に戻してくれるのかと思いきや、戻らないみたい。

イメージ一覧を表示
# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              4744417607b3        10 minutes ago      472MB
php                 7.2-fpm             6ff5bc1d81f0        7 days ago          398MB

どこでこけたんだろう。
と思って、元の記事のコメント見てみた。

自分と同じようにComposerのインストールで引っかかった方は、
最新のハッシュ値を下のサイトで確認して書き換えると上手くいくと思います。
https://getcomposer.org/download/

ふむふむ、確かにリンク先確認したらハッシュ値が違った。
※ていうか、べた書きなことに少し疑問盛ってたけど、ちゃんと追っておけばよかった。

Composerのインストールはバージョンによってハッシュ値が異なってしまう関係上、毎回Dockerfileを書き換えのは面倒なので以下の書き方をすると書き換える必要がなくて便利です!

# 変更前
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

# 変更後
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

なにこれ天才かよ。。。

Dockerfile
FROM php:7.2-fpm
COPY php.ini /usr/local/etc/php/

RUN apt-get update \
  && apt-get install -y zlib1g-dev mariadb-client \
  && docker-php-ext-install zip pdo_mysql

#Composer install
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin


WORKDIR /var/www

RUN composer global require "laravel/installer"

すっきりした。
もう一回実行してみる。

docker起動(2回目)
# docker-compose up -d
ERROR: Service 'php' failed to build: The command '/bin/sh -c composer global require "laravel/installer"' returned a non-zero code: 1

こけたけど、さっきよりは処理進んでるっぽい。
赤字の部分にこんなのがあった。

[ErrorException]
proc_open(): fork failed - Cannot allocate memory

これ、知ってるぞ
Docker云々の前、普通にLaravelデビューするときに出てきた。
その時と同じ状況でやってるんだから、同じことが起きても不思議じゃないよね。

https://akamist.com/blog/archives/236
以前はここに記載の方法「Swap領域の有効化」でうまくいったけど、Dockerでやってる今はどうなんだろう。
試しにやってみる。

# /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 14.0341 s, 76.5 MB/s

# /sbin/mkswap /var/swap.1
mkswap: /var/swap.1: insecure permissions 0644, 0600 suggested.
Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
no label, UUID=672b24c0-04f2-4b5b-b6ce-b3bd6ad3a764

# /sbin/swapon /var/swap.1
swapon: /var/swap.1: insecure permissions 0644, 0600 suggested.

準備OK。いざ。

docker起動(3回目)
# docker-compose up -d
(略)
Creating php     ... done
Creating db-host ... done
Creating nginx   ... done

# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS                               NAMES
c111408c89a5        nginx               "nginx -g 'daemon of…"   2 minutes ago       Up 2 minutes                0.0.0.0:80->80/tcp                  nginx
1d5bc8716afa        mysql:5.7           "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes                0.0.0.0:3306->3306/tcp, 33060/tcp   db-host
94d3abb55903        project_php         "docker-php-entrypoi…"   2 minutes ago       Up 2 minutes                9000/tcp                            php
93eae4fcf1cc        f959b6f2dc70        "/bin/sh -c 'compose…"   12 minutes ago      Exited (1) 11 minutes ago                                       upbeat_saha
7e3ab5b0fb47        4744417607b3        "/bin/sh -c 'php com…"   45 minutes ago      Exited (1) 45 minutes ago                                       sleepy_hellman
※下の2つはこけた時のなので、後で消した

脳汁☆全開

続きもやっていこう。

phpコンテナに入る
# docker-compose up -d
root@94d3abb55903:/var/www#

Laravelプロジェクト作成
# laravel new
(略)
Application ready! Build something amazing.

さっくりと成功しました。

動作確認

事前にEC2のセキュリティグループに手を加えておくのを忘れない。

こけた。
(画面とりわすれちゃったけど)LaravelのPermission Denied的なやつがでてくる。

Laravelまわりのディレクトリのパーミッション変更が必要だった。
「これってセキュリティ的にどうなの?」とは思う。
けど現段階ではまだそこまで考えなくていいので、無心で変えていく。

# sudo chmod 2775 /var/project/server
# find /var/project/server -type d -exec sudo chmod 2775 {} +
# find /var/project/server -type f -exec sudo chmod 0664 {} +
# sudo chmod -R 777 /var/project/server/storage/
# sudo chmod -R 777 /var/project/server/bootstrap/cache

うまくいった。今回はここまで。
20200305_DockerLaravelTest.PNG

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

【Rails不定期連載】#1 DockerでRailsの環境構築

アウトプットの練習 & 初心に帰って基礎からRailsを見直してこうと思います。
不定期に更新します。

今回はRuby on Railsの環境構築。

今回はDockerでRailsチュートリアルを進めていくためのRailsプロジェクトを作ります。
rbenvなどを用いたローカルでの環境構築ではないです。

前置き

前提として...

  • 以下の場合はローカルでの環境構築を勧めます
    • railsの環境構築1度もしたことない
    • dockerを使った開発をしたことがない(Dockerfileの記述がわからない) ### アプリケーション要件
    • ruby 2.6.5
    • rails 6.2.0
    • sqlite3
    • webpacker、springはとりあえず不要なので除く

すごいざっくりですが、こんなイメージ、コンテナを作るのがゴールです。

レッツ環境構築

STEP1 rails newコマンドまでの準備

PJ用のディレクトリを作成してその中で作業していきます。

まずは必要になるファイルを用意しましょう。

touch Dockerfile docker-compose.yml Gemfile Gemfile.lock .gitignore

Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.5'

gem 'rails', '~> 6.0.2', '>= 6.0.2.1'

Dockerfile
FROM ruby:2.6.5-alpine

ENV LANG="C.UTF-8" \
    PACKAGES="curl-dev build-base alpine-sdk tzdata sqlite-dev less ruby-dev nodejs"

RUN apk update && \
    apk add --no-cache --update $PACKAGES

WORKDIR /var/www

COPY ./ ./

RUN gem install bundler && \
    bundle install -j4

EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0", "-p", "3000"]

docker-compose.yml
version: '3'
services:
  app:
    build:
      context: ./
      dockerfile: Dockerfile
    volumes:
      - ./:/var/www
    ports:
      - "3000:3000"
    tty: true
    stdin_open: true
    restart: always

.gitignore
# Ignore bundler config.
/.bundle

# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
/db/*.sqlite3-*

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep

# Ignore uploaded files in development.
/storage/*
!/storage/.keep

/public/assets
.byebug_history

# Ignore master key for decrypting credentials and more.
/config/master.key

.idea
.vscode
.DS_store

一旦ここまで作ってしまいます。
(.gitignoreはお好みあれば)

ここまで作ったらイメージを作成します。
docker-compose build

STEP2 Railsプロジェクトの作成、微修正

buildが完了したら、いよいよRailsプロジェクトを作成します。

-d sqlite -> 使用DBをsqlite3を選択
-B -> プロジェクト作成後のbundle installをしない(修正するからスキップで)
--skip-webpack-install -> プロジェクト作成後のwebpacker:installをしない
--skip-spring -> プロジェクト作成後のspringのinstallをしない

docker-compose run --rm app rails new -d sqlite3 -B --skip-webpack-install --skip-spring .

コマンド実行すると、いくつかのファイルがもう存在するけどどうする〜?みたいに聞かれます。
.gitignoreファイルは上書きなし、Gemfileは上書きしてしまいましょう。

    conflict  .gitignore
Overwrite /var/www/.gitignore? (enter "h" for help) [Ynaqdhm] n
        skip  .gitignore
    conflict  Gemfile
Overwrite /var/www/Gemfile? (enter "h" for help) [Ynaqdhm] Y
       force  Gemfile

Gemfileにあるwebpackerの記述を消しましょう

Gemfile
# 下記二行を削除
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'

サーバー立ち上げた後にsw.jsが無いとエラーを吐きまくるので仮で作っておきましょう。
touch public/sw.js

ここまでくればもう少し、bundle installとdbの作成、マイグレーションを実行します。

その前にgemを更新するため、再度ビルドしてあげましょう。

docker-compose build

docker-compose run --rm app rails db:create

docker-compose run --rm app rails db:migrate

STEP3 Railsプロジェクトの起動

あとはコマンド一つでRailsサーバーが立ち上がります。
docker-compose up -d

http://localhost:3000 で立ち上がるのを確認しましょう。

hello Rails

やったぜ。

終わりに

出来上がりのソースコードはこちらに置いてあります。(変更あるかもしれませんが)

RubyMineを最近購入したのでこれからウッキウキでコード書こうと思います。

Railsに関しての記事をこれから不定期ですが粛々とアップしていきますのでよければ!

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

DockerでNGINX + NGINX Unit + MySQLの環境を構築

Dockerの導入

以前、NGINX + NGINX Unit + Flaskの環境を構築しました。

NGINX + NGINX Unit + Flask で PythonのWeb アプリを動かす

前回はVagrantとVirtualBoxで構築しましたが、今回はDockerで構築していこうと思います。
前回と同様に、WebサーバーにNGINXを、APサーバーにNGINX Unitを、フレームワークにFlaskを使用します。
更に今回はデータベースとしてMySQLを追加し、WEB <-> AP <-> DBの環境を構築をしていきます。

以下の図のようなイメージです。(本来コンテナはホスト内で起動しますが、わかりやすように分けています)

docker1.png

順を追って構築していくため、できたものをみたい方はGitHubに上げてありますのでそちらをどうぞ。

https://github.com/txkxyx/docker-web

環境

以下の環境で構築していきます。

  • ホスト
    • OS : macOS Catalina 10.15.3
    • Docker : 19.03.5
  • コンテナ
    • Python : 3.7.3
    • Flask : 1.1.1
    • NGINX : 1.17.7
    • NGINX Unit : 1.14.0
    • MySQL : 8.0.18
    • Flask SQLAclchemy : 2.4.1

ディレクトリ構成は以下のようにします。

./web
    |- db                   // DB用
    |- nginx                // NGINX用
    |- python               // NGINX Unit・ソースファイル用
    |    |- src
    |- docker-compose.yml

では始めていきます。

Dockerfiletとdocker-composeの設定値

Dokerfileとdocker-composeで使用する設定値を簡単にまとめておきます。

Dockerfileの設定値

詳しくは公式のDockerfileリファレンスを参照してください。

https://docs.docker.com/engine/reference/builder/

設定値 概要
FROM 使用するイメージを指定する。
WORKDIR 作業ディレクトリを指定する。この宣言以降はコンテナ内の指定したパスで作業を行う。
COPY ホストからコンテナに、指定したディレクトリやファイルをコピーする。ホスト コンテナの順で指定する。.dockerignoreで指定したファイルは対象外となる。
RUN 指定したコマンドを現時点のコンテナ内で実行する。(ビルド時に実行するコマンド)
CMD コンテナ起動時に実行するコマンドを指定する。(起動時に実行するコマンド)

docker-composeの設定値

詳しくは公式のリファレンスを参照してください。

https://docs.docker.com/compose/compose-file/

設定値 概要
version Docker Engineが対応するファイルフォーマットのバージョン
services アプリケーションを構成する各要素
build 起動するコンテナのDockerfileがあるディレクトリを指定。子要素で、context(DockerfileのあるディレクトリまたはGithubURL)args(Dockerfileに渡す引数)などを指定できる 。
image 起動するコンテナが使用するイメージを指定する。
command docker-compose up を実行した際に実行されるコマンド
ports コンテナが公開するポートを指定します。ホスト:コンテナもしくはコンテナのポートのみ指定します。
expose リンクするコンテナのみに公開するコンテナのポートを指定します。ホストには公開されません。
environment 起動するコンテナの環境変数を指定します。
volumes コンテナにマウントするホストのディレクトリを指定します。ホスト:コンテナの形式でパスを指定します。
container_name 起動するコンテナのコンテナ名を指定します。
depends_on サービス間の依存関係を指定します。指定したサービス名が先に起動します。

DBコンテナの構築

まずはMySQLのコンテナを構築していきます。
イメージはこんな感じです。

docker2.png

docker-compose.ymlを作成します。

web/docker-compose.yml
version: "3"

services:
    db:
        image: mysql
        command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
        ports:
            - "33306:3306"
        expose:
            - "3306"
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test
        volumes:
            - ./db/init:/docker-entrypoint-initdb.d
        container_name: app_db

コンテナの初期起動時にデータベースを作成するように、dbディレクトリ内にinitディレクトリを作成し、createdatabase.sqlを作成します。

web/db/init/createdatabase.sql
CREATE DATABASE app;
USE app;

CREATE TABLE users(
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255),
    email VARCHAR(255)
);

INSERT INTO users(name,email) VALUES('sample','sample@sample.com');
INSERT INTO users(name,email) VALUES('test','test@test.com');
INSERT INTO users(name,email) VALUES('app','app@app.com');

GRANT ALL ON app.* TO test;

以上の設定でdocker-composeでMySQLのコンテナを起動します。

$ docker-compose up
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
bef9a864276c        mysql               "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes        33060/tcp, 0.0.0.0:33306->3306/tcp   app_db

docker psの結果にapp_dbが表示されればコンテナを起動できています。
一度コンテナ内に入って、データベースが作成されているかを確認します。

$ docker exec -it app_db bash
root@00000000000:/# mysql -u test -p
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| app                |
| information_schema |
+--------------------+
2 rows in set (0.00 sec)
mysql> use app;
mysql> select * from users;
+----+--------+-------------------+
| id | name   | email             |
+----+--------+-------------------+
|  1 | sample | sample@sample.com |
|  2 | test   | test@test.com     |
|  3 | app    | app@app.com       |
+----+--------+-------------------+
3 rows in set (0.01 sec)

appというデータベースが作成されていることが確認できます。更に、createdatabase.sqlのテーブルとデータが作成されていることが確認できます。
MySQLの構築は以上です。

APコンテナの構築

APサーバーとしてNGINX Unitを、実行環境にPython3を、フレームワークとしてFlaskを使用したコンテナを構築します。
NGINX Unitの公式ドキュメントを参考に構築していきます。
イメージはこんな感じです。

docker3.png

NGINX Unitのコンテナの起動

まずは、NGINX UnitのイメージからPython3とFlaskの環境を構築します。開発環境の最小単位はこれでいいかもしれません。
web/pythonディレクトリにDockerfileを追加します。

web/python/Dorckerfile
FROM nginx/unit:1.14.0-python3.7

WORKDIR /usr/src/app

COPY src .

RUN apt update && apt install -y python3-pip                               \
    && pip3 install --no-cache-dir -r ./requirements.txt                            \
    && rm -rf /var/lib/apt/lists/* 

CMD ["sleep","infinity"]

Docker Hubのnginx/unitのサイトから、NGINX UnitのPython3.7用のイメージを使用します。

次に、pipでライブラリを一括でインストールできるように、web/python/srcディレクトリにrequirements.txtを作成します。

web/python/src/requirements.txt
Flask == 1.1.1
flask-sqlalchemy == 2.4.1
PyMySQL == 0.9.3

docker-compose.ymlにNGINX Unitのコンテナの設定を追記します。

docker-compose.yml
version: "3"

services:
    db:
        image: mysql
        ports:
            - "33306:3306"
        expose:
            - "3306"
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test
        volumes:
            - ./db/init:/docker-entrypoint-initdb.d
        container_name: app_db
    # ↓↓追記
    ap:
        build: ./python
        ports:
            - "8080:8080"
        environment:
            TZ: "Asia/Tokyo"
        container_name: app_ap
        depends_on:
            - db

作成した'Dockerfile'はweb/pythonのディレクトリに存在するので、buildでその場所を指定します。
サーバーのポートは8080をホストに公開するようにします。
起動しているDockerコンテナを停止してから、docker-compose buildでビルドしてからコンテナを起動します。

$ docker-compose down
$ docker-compose build --no-cache
$ docker-compose up
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
daf4ddc7c11a        web_ap              "sleep infinity"         41 seconds ago      Up 40 seconds       0.0.0.0:8080->8080/tcp               app_ap
565eb32e6a39        mysql               "docker-entrypoint.s…"   43 seconds ago      Up 41 seconds       33060/tcp, 0.0.0.0:33306->3306/tcp   app_db

MySQLのコンテナのapp_dbと、NGINX Unitのコンテナのapp_apが起動していることが確認できます。
NGINX Unitのコンテナに入り、requirements.txtのライブラリがインストールされているかを確認します。

$ docker exec -it app_ap bash
root@00000000000:/# python3 -V
Python 3.7.3
root@00000000000:/# pip3 freeze
Flask==1.1.1
Flask-SQLAlchemy==2.4.1
PyMySQL==0.9.3

上記のライブラリ以外にも、SQLAlchemyJinja2などがインストールされています。
ここまでNGINX Unitのコンテナの起動は完了です。続いて、Flaskの実装を行います。

Flaskアプリケーションの実装

Flaskアプリケーションの実装をします。作成するファイルとディレクトリは以下のようになります。

./web
    |- db
    |   |- init
    |       |- createdatabase.sql
    |- nginx  
    |- python
    |   |- src
    |   |   |- app.py           ← 追加
    |   |   |- config.json      ← 追加
    |   |   |- config.py        ← 追加
    |   |   |- run.py           ← 追加
    |   |   |- users.py         ← 追加
    |   |   |- requirements.txt
    |   |   |- templates        ← 追加
    |   |       |- list.html    ← 追加
    |   |- Dockerfile           ← 更新
    |- docker-compose.yml

各ファイルは以下のように実装します。

config.py

まずは、DBの接続先などの設定クラスを実装するconfig.pyです。
ホスト先は、DBコンテナのコンテナ名app_dbで指定します。

web/python/src/config.py
class Config(object):
    '''
    Config Class
    '''
    # DB URL
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://test:test@app_db:3306/app?charset=utf8'

app.py

次にFlaskアプリケーションを起動するapp.pyです。
config.from_object()でアプリケーションの設定クラスを呼び込み、SQLAlchemy()でFlaskアプリケーションでSQLAchemyが使えるように初期化を行います。

web/python/src/app.py
from config import Config
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# Create Flask Application
application = Flask(__name__)

# Set Config Class
application.config.from_object(Config)

# Set DB
db = SQLAlchemy(application)

users.py

次にusersテーブルのModelクラスを作成します。
db.Modelクラスを継承したUsersクラスを作成します。

web/python/src/users.py
from app import db

class Users(db.Model):
    '''
    Users Table Model
    '''
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    email = db.Column(db.String(255))

    def __init__(self,name,email):
        self.name = name
        self.email = email

run.py

次に、Flaskアプリケーションの起動とルーティングのモジュールrun.pyです。
レスポンスにテンプレートファイルを使用するので、render_template()でテンプレートファイルとオブジェクトを指定します。

web/python/src/run.py
from app import application
from users import Users
from flask import render_template

@application.route('/list')
def index():
    users = Users.query.order_by(Users.id).all()
    return render_template('list.html', users=users)

if __name__ == '__main__':
    application.run(host='0.0.0.0', port='8080')

list.html

次にテンプレートファイルとなるlist.htmlを作成します。
render_template()usersオブジェクトが渡されるので、テンプレートエンジンであるJinja2を使用して実装します。

web/python/src/templates/list.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flask Sample</title>
</head>
<body>
    <h1>Flask Sample</h1>
    <table border="1" style="border-collapse: collapse">
        <thead>
            <tr>
                <th >Id</th>
                <th >Name</th>
                <th >EMail</th>
            </tr>
        </thead>
        <tbody>
            {% for user in users %}
                <tr>
                    <td>{{user.id}}</td>
                    <td>{{user.name}}</td>
                    <td>{{user.email}}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
</body>
</html>

Dockerfile

Dockerfileを更新します。

web/python/Dorckerfile
FROM nginx/unit:1.14.0-python3.7

WORKDIR /usr/src/app

COPY src .

RUN apt update && apt install -y python3-pip                               \
    && pip3 install --no-cache-dir -r ./requirements.txt                            \
    && rm -rf /var/lib/apt/lists/*
# ↓↓削除

config.json

最後にNGINX Unitの設定ファイルconfig.jsonを追加します。

web/python/src/config.json
{
  "listeners": {
    "*:8080": {
      "pass": "applications/app"
    }
  },

  "applications": {
    "app": {
      "type": "python",
      "processes": 2,
      "path": "/usr/src/app/",
      "module": "run"
    }
  }
}

実装は以上です。

ビルドしてからコンテナを起動してみましょう。

$ docker-compose down
$ docker-compose build --no-cache
$ docker-compose up
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
daf4ddc7c11a        web_ap              "sleep infinity"         41 seconds ago      Up 40 seconds       0.0.0.0:8080->8080/tcp               app_ap
565eb32e6a39        mysql               "docker-entrypoint.s…"   43 seconds ago      Up 41 seconds       33060/tcp, 0.0.0.0:33306->3306/tcp   app_db

app_apのコンテナの起動後に、コンテナにアクセスしてNGINX Unitの設定ファイルを設定します。

$ docker exec -it app_ap bash
root@00000000000:/# curl -X PUT --data-binary @config.json --unix-socket /var/run/control.unit.sock http://localhost/config
{
    "success": "Reconfiguration done."
}

ブラウザで、http://localhost:8080/listにアクセスして画面が表示されます。

docker4.png

これでAPコンテナの構築は終了です。

Webコンテナの構築

最後にWEBサーバーのNGINXのコンテナを構築していきます。
これでNGINX <-> NGINX Unit <-> Flask <-> MySQLの構成になります。

docker1.png

追加、更新するファイルは以下のようになります。

./web
    |- db
    |   |- init
    |       |- createdatabase.sql
    |- nginx
    |   |- Dockerfile       ← 追加
    |   |- index.html       ← 追加
    |   |- nginx.conf       ← 追加
    |- python
    |   |- src
    |   |   |- __init__.py
    |   |   |- app.py
    |   |   |- config.json
    |   |   |- config.py
    |   |   |- run.py
    |   |   |- users.py
    |   |   |- requirements.txt
    |   |   |- templates
    |   |       |- index.html
    |   |- Dockerfile
    |- docker-compose.yml   ← 更新

まずはトップページとなるindex.htmlを作成します。

web/nginx/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Index</title>
</head>
<body>
    <h1>Index</h1>
    <a href="/list">List</a>
</body>
</html>

次にNGINXDockerfileを作成します。

FROM nginx

WORKDIR /var/www/html

COPY ./index.html ./

CMD ["nginx", "-g", "daemon off;","-c","/etc/nginx/nginx.conf"]

次に、NGINXの設定ファイルを作成します。前回の記事で紹介した設定ファイルから、APサーバーのホストをDocker用に変更します。

nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;
    server_tokens off;

    keepalive_timeout  65;

    #gzip  on;

    upstream unit-python {
        server app_ap:8080; # container_nameで指定
    }
    server {
        listen 80;
        server_name localhost;

        # トップページを表示
        location  / {
            root /var/www/html;
        }

        # /listはAPコンテナにルーティング
        location  /list {
            proxy_pass http://unit-python;
            proxy_set_header Host $host;
        }
    }
}

最後にdocker-composeを更新します。

docker-compose.yml
version: "3"

services:
    db:
        image: mysql
        ports:
            - "33306:3306"
        expose:
            - "3306"
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test
        volumes:
            - ./db/init:/docker-entrypoint-initdb.d
        container_name: app_db

    ap:
        build:
            context: ./python
            args:
                project_directory: "/src/"
        # ↓↓更新
        expose:
            - "8080"
        volumes:
            - "./python/src:/projects"
        environment:
            TZ: "Asia/Tokyo"
        container_name: app_ap
        depends_on:
            - db
    # ↓↓追加
    web:
        build: ./nginx
        volumes:
            - ./nginx/nginx.conf:/etc/nginx/nginx.conf
        ports:
            - "80:80"
        environment:
            TZ: "Asia/Tokyo"
        container_name: "app_web"
        depends_on:
            - ap

ビルドしてからコンテナを起動してみましょう。

$ docker-compose down
$ docker-compose build --no-cache
$ docker-compose up
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
5b0f06b89db4        web_web             "nginx -g 'daemon of…"   2 minutes ago       Up 23 seconds       0.0.0.0:80->80/tcp                   app_web
625f3c025a82        web_ap              "/usr/local/bin/dock…"   2 minutes ago       Up 2 minutes        8080/tcp                             app_ap
fe5bf54411a2        mysql               "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        33060/tcp, 0.0.0.0:33306->3306/tcp   app_db

app_apのコンテナの起動後に、コンテナにアクセスしてNGINX Unitの設定ファイルを設定します。

$ docker exec -it app_ap bash
root@00000000000:/# curl -X PUT --data-binary @config.json --unix-socket /var/run/control.unit.sock http://localhost/config
{
    "success": "Reconfiguration done."
}

ブラウザで、http://localhost:80にアクセスするとトップページのindex.htmlが表示されます。(8080ポートではアクセスできません)

docker5.png

リンクとなっているListを押下すると、Flaskアプリケーションのlist.htmlが表示されます。

docker6.png

以上でNGINXの構築は終了です。

まとめ

DockerでNGINX + NGINX Unit + MySQLの環境を構築することができました。
あとはアプリケーションを作り込むだけです。

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

Docker① Dockerはじめました。

師匠「環境構築にはDockerを使いましょう」
ぼく「承知っす!!!(Docker...?)」
ってことでDockerについて調べてみました。

Dockerとは

参考

Docker入門(第一回)~Dockerとは何か、何が良いのか~

要約

  • Dockerは、コンテナ型の仮想環境を配布・実行するためのプラットフォーム。

  • 仮想マシンとは違う。

    • 仮想マシン ホストマシン上でハイパーバイザを利用してゲストOSを動かす。そのうえでミドルウェアなどを動かす。
    • Docker ホストマシンのカーネルを利用して、プロセスやユーザを隔離する。従って軽量・高速。
  • ミドルウェアのインストールや各種環境設定をコード化して管理する。

    1. コード化されたファイルを共有することで、どこでも誰でも同じ環境が作れる。
    2. 作成した環境を配布しやすい。
    3. スクラップ&ビルドが容易にできる。
  • Dockerイメージは、Web上のDocker Hubで公開されている。
    Dockerイメージを取得すれば、すでに必要なミドルウェアなどがインストールされているDockerコンテナを起動できる。

感想

仮想マシンより軽快に動くらしい。確かに仮想マシンってもっさりしている印象あるよね。
「コード化して管理」ってなんか今風な感じ。
いまいちイメージわかないけど、とりあえず触ってみよう。

Dockerセットアップ、コンテナ起動

参考

Docker入門(第二回)~Dockerセットアップ、コンテナ起動~

Dockerのインストール

ハマった。
例はCentOSだけど、Linuxが好きなのでAmazon Linux2に入れようとした。

いくらやっても
sudo amazon-linux-extras install docker
これでこける。

失敗例
# sudo amazon-linux-extras install docker
Installing docker
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Cleaning repos: amzn2-core amzn2extra-docker docker-ce-stable
12 metadata files removed
6 sqlite files removed
0 metadata files removed
(略)
Resolving Dependencies
--> Running transaction check
---> Package docker.x86_64 0:18.09.9ce-2.amzn2 will be installed
--> Processing Dependency: runc = 1.0.0 for package: docker-18.09.9ce-2.amzn2.x86_64
--> Processing Dependency: containerd = 1.2.6 for package: docker-18.09.9ce-2.amzn2.x86_64
--> Processing Dependency: pigz for package: docker-18.09.9ce-2.amzn2.x86_64
--> Processing Dependency: libcgroup for package: docker-18.09.9ce-2.amzn2.x86_64
--> Running transaction check
---> Package containerd.io.x86_64 0:1.2.13-3.1.el7 will be installed
--> Processing Dependency: container-selinux >= 2:2.74 for package: containerd.io-1.2.13-3.1.el7.x86_64
---> Package libcgroup.x86_64 0:0.41-21.amzn2 will be installed
---> Package pigz.x86_64 0:2.3.4-1.amzn2.0.1 will be installed
--> Finished Dependency Resolution
Error: Package: containerd.io-1.2.13-3.1.el7.x86_64 (docker-ce-stable)
           Requires: container-selinux >= 2:2.74
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest
Installation failed. Check that you have permissions to install.

調べてみたら、こんな記事が。
そうかそうか、docker-ce.repoが邪魔だったのね。
なんでCentOSの記事をそのまま引用したんだろう、反省。

削除して、もう一回
sudo amazon-linux-extras install docker
でいけました。うんうん、知ってた知ってた。

Dockerを動かしてみる

準備

Dockerサービス起動
# systemctl start docker.service

サービスの起動確認
# systemctl status docker

Dockerの自動起動設定
# systemctl enable docker

試しにDockerコマンド実行
# docker info

この辺は特に問題なくいきました。

DockerイメージとDockerコンテナ

  • まず、Dockerイメージがある。
  • Dockerイメージをもとに、Dockerコンテナを起動する。

初期状態

イメージ一覧を表示
# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

初期状態では、イメージはない。
従ってヘッダーのみが表示されている。

コンテナ一覧を表示
# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

コンテナも起動していないため、ヘッダーのみが表示されている。

hello-worldイメージを使ってコンテナを動かす

イメージ取得→起動
# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:fc6a51919cfeb2e6763f62b6d9e8815acbf7cd2e476ea353743570610737b752
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/
イメージ一覧を表示
# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        14 months ago       1.84kB

イメージが追加されていることを確認。

コンテナ一覧を表示
# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
24c4702a238c        hello-world         "/hello"            About a minute ago   Exited (0) About a minute ago                       laughing_pascal

コンテナも起動していることを確認。
「STAUS」が「Exited」になっているため、正確には停止している。
(hello-worldイメージは、MSGを出漁するだけなので停止で問題ない。)

イメージ、コンテナの削除

コンテナ削除
# docker rm <コンテナ名>
 もしくは
# docker rm <CONTAINER ID>
イメージ一覧を表示
# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        14 months ago       1.84kB

イメージは消えていない。

コンテナ一覧を表示
# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

コンテナは消えている。

イメージ削除
# docker rmi <イメージ名>
 もしくは
# docker rmi <IMAGE ID>
イメージ一覧を表示
# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

イメージも消えた。

コンテナ一覧を表示
# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

もちろん、コンテナは消えている。

Nginxイメージの使用

Nginxイメージの取得
# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
68ced04f60ab: Pull complete
c4039fd85dcc: Pull complete
c16ce02d3d61: Pull complete
Digest: ***
Status: Downloaded newer image for nginx:latest

Nginxコンテナの起動
# docker run -d --name nginx-container -p 8181:80 nginx

起動オプションは以下の通り。

オプション 意味
-d バックグラウンド実行
--name <任意の名前> コンテナ名を指定
-p <ホスト側のPORT>:<コンテナ側のPORT> PORTを指定

http://<サーバのIP>:8181/
で、Nginxにアクセス可能。
(EC2の場合、セキュリティグループの設定変更が必要)

Dockerコマンドについて

参考

Docker入門(第三回)~各種dockerコマンドとDockerイメージ作成について~
Docker コマンドチートシート

各種コマンドによる操作

  • Dockerイメージ取得、イメージ一覧確認
  • コンテナ起動、コンテナ一覧確認
  • コンテナへのログイン
  • ファイルコピー(ホスト→コンテナ内)
  • ファイルコピー(コンテナ内→ホスト)
  • コンテナからDockerイメージ作成
  • コンテナ起動、停止
  • コンテナ削除

など。参考のリンク先をみれば良いので割愛。

ホスト側とのディレクトリ共有

起動時にvオプションをつけることで、ホスト側のディレクトリとコンテナ内のディレクトリを共有することが可能。
使用例としては、ログの出力先など。
例えばコンテナ内でログを出力していた場合、コンテナの停止とともに消えてしまうため。

オプション 意味
-v <ホスト側ディレクトリ>:<コンテナ側ディレクトリ> 両ディレクトリを共有にする
ディレクトリ共有した状態で起動
# docker run -it -d -p 18080:8080 -v /root/tomcat-container/logs:/share/logs --name tomcat centos:7

イメージの作成

ここまではイメージからコンテナを作ってきたが、コンテナからイメージを作ることもできる。

コンテナの停止(やらなくても作成できるみたい。停止したほうが安全?)
# docker stop nginx-container

nginx-containerコンテナから、nginx2イメージを作成
# docker commit nginx-container nginx_2

イメージを確認
# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx_2             latest              4a4ce52ad449        6 seconds ago       127MB
nginx               latest              a1523e859360        6 days ago          127MB

nginx_2イメージが作成されている。
試しに作成したイメージからコンテナを起動してみる。

Nginx_2コンテナの起動
# docker run -d --name nginx2-container -p 8182:80 nginx_2

起動したコンテナの確認
# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
53e414bab96d        nginx_2             "nginx -g 'daemon of…"   41 seconds ago      Up 39 seconds       0.0.0.0:8182->80/tcp   nginx2-container
4e29184909ff        nginx               "nginx -g 'daemon of…"   29 hours ago        Up 29 minutes       0.0.0.0:8181->80/tcp   nginx-container

確認できたので止める
# docker stop nginx2-container

停止の確認
# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                  NAMES
53e414bab96d        nginx_2             "nginx -g 'daemon of…"   2 minutes ago       Exited (0) 9 seconds ago                          nginx2-container
4e29184909ff        nginx               "nginx -g 'daemon of…"   29 hours ago        Up 31 minutes              0.0.0.0:8181->80/tcp   nginx-container

コンテナの削除
# docker rm nginx2-container

削除の確認
# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
4e29184909ff        nginx               "nginx -g 'daemon of…"   29 hours ago        Up 31 minutes       0.0.0.0:8181->80/tcp   nginx-container

Dockefileについて

参考

Docker入門(第四回)~Dockerfileについて~

Dockerfileって何?

公開されているDockerイメージに、「必要なパッケージやアプリを追加する」「各種設定をする」など少し手を加えておきたい場合に使用するもの。
Dockerfile内に、実行したい内容を記述する。

Dockerfileを使用してみる

…と思ったけど、参考記事の例はtomcatだしちょっと微妙かなと。
どうせならLaravel環境作成したりしたいなと。

そんなことを思ってたらこんなものがあった。
Dockerを使ってLaravel開発環境構築
最高っす。ドンピシャっす。
というわけで、実際に動かすのは別の機会にすることにした。

コンテナ間通信について

参考

Docker入門(第五回)〜コンテナ間通信〜

コンテナ間通信

コンテナ同士の通信をするためには、以下2通りの方法がある。
1. Dockerネットワークを作成し、コンテナ名で接続
1. --link オプションを使用して起動する

Dockerネットワークの作成

例として、Dockerネットワーク(bridgeタイプ)を作成する。
その他のタイプについてはこちら参照とのこと。

「network1」というDockerネットワークを作成
# docker network create network1

Dockerネットワークの一覧を表示
# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
064b0ea3a75c        bridge              bridge              local
7281bec71e9e        host                host                local
3585fc587596        network1            bridge              local
272c5bc211eb        none                null                local

「network1」が存在することが確認できる。
デフォルトで「bridge」も存在しているが、これはDNS設定がされておらず名前解決できないため、コンテナ名を使用したコンテナ間通信ができないらしい。

Dockerネットワークの詳細を表示
# docker network inspect network1
[
    {
        "Name": "network1",
        "Id": "3585fc587596ba17195364d8aea2e77add0978813782bfb21b15486153df109c",
        "Created": "2020-03-04T17:38:12.168101241Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
「network1」を使用したコンテナを作成
# docker run -d --name nginx3-container --network network1 -p 8183:80 nginx_2

起動したコンテナを確認
# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
20158137a4ce        nginx_2             "nginx -g 'daemon of…"   3 seconds ago       Up 1 second         0.0.0.0:8183->80/tcp   nginx3-container
1487009fb41a        nginx_2             "nginx -g 'daemon of…"   12 minutes ago      Up 12 minutes       0.0.0.0:8182->80/tcp   nginx2-container
4e29184909ff        nginx               "nginx -g 'daemon of…"   35 hours ago        Up 6 hours          0.0.0.0:8181->80/tcp   nginx-container

なおコンテナ間通信をする場合、PORT番号はコンテナ内部で使用しているPORTを指定すること。


MySQLのコンテナを以下のコマンドで作成した場合、ホスト側のPORTは19090、コンテナ内のPORTは9090となる。

# docker run --name mysql --network wordpress-network -p 19090:9090 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7

この場合、コンテナ間通信で指定するPORTは「9090」となる。

--linkオプションによる通信

あらかじめ、mysqlコンテナを「some-mysql」という名前で作成
# docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7

--linkオプションを用いて「some-mysql:mysql(wordpressコンテナ内で使用しているMySQLのホスト名)」を指定
# docker run --name some-wordpress -e WORDPRESS_DB_PASSWORD=my-secret-pw --link some-mysql:mysql -d -p 8080:80 wordpress

Docker Composeについて

参考

Docker入門(第六回)〜Docker Compose〜

Docker Composeとは

Docker Composeは、複数のコンテナで構成されるアプリケーションについて、Dockerイメージのビルドや各コンテナの起動・停止などをより簡単に行えるようにするツールです。

複数のコンテナを同時に起動したり、オプションを省略できるもの(?)

Docker Composeのインストール

Dockerがインストールされている環境で以下を実行
# 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 version 1.21.2, build a133471

docker-compose.ymlについて

Docker Composeを使用する場合、「docker-compose.yml」というファイルが必要となる。
このファイルには、以下のような情報を定義する。
- Dockerイメージをビルドするための情報(使用するDockerfile、イメージ名など)
- コンテナ起動するための情報(ホストとの共有ディレクトリ設定やポートフォワードなどの起動オプションなど)
- 使用するDockerネットワーク

mysqlとwordpressのコンテナを起動するrunコマンド

# docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7
# docker run --name some-wordpress -e WORDPRESS_DB_PASSWORD=my-secret-pw --link some-mysql:mysql -d -p 8080:80 wordpress

これを「docker-compose.yml」に記載すると、以下の通り。

docker-compose.yml
version: '3'
services:

  wordpress:
    image: wordpress
    container_name: some-wordpress
    restart: always
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_PASSWORD: my-secret-pw

  mysql:
    image: mysql:5.7
    container_name: some-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: my-secret-pw

自分で作成した(公開でない)Dockerイメージを使用する場合(例)

docker-compose.yml
version: '3'
services:
  tomcat:
    build: ./tomcat
    image: tomcat-image
    container_name: tomcat1
    ports:
      - 8081:8080
    volumes:
      - ./tomcat/share/logs:/share/logs

runコマンドのオプションと「docker-compose.yml」の記載内容を比較すると、以下の通り。

設定内容 runコマンドのオプション docker-compose.yml
コンテナ名 --name container_name
環境変数 -e environment
ポートフォワード -p ports
使用するDockerイメージ コマンドの最後 image
Dockerfileの指定 docker buildコマンド build
共有ディレクトリ -v volumes:

「--link」オプションに対応するものはないが、そもそも「docker-compose.yml」を使用した場合は自動でDockerネットワークを作成するため、自動でservice名で名前解決ができるようになっている。

「docker-compose.yml」を使用してコンテナを起動する。

# cd <docker-compose.ymlが置かれているディレクトリ>

docker-composeによる起動
# docker-compose up -d

起動の確認
# docker-commpose ps
Name                   Command               State          Ports
------------------------------------------------------------------------------
some-mysql       docker-entrypoint.sh mysqld      Up      3306/tcp, 33060/tcp
some-wordpress   docker-entrypoint.sh apach ...   Up      0.0.0.0:8080->80/tcp

次は、Laravel環境を構築をしてみる。

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

SSHした先のリモートサーバー上のDockerコンテナをVScodeで直接編集する。

概要

リモートワークが提唱される、そんな世の中だから。

開発中に、SSHを使ってリモートサーバーにアクセスすることがある。
さらに、そのリモートサーバーの中でDockerコンテナを作って開発をしたい時、ボリュームをマウントしていればリモートサーバー上のファイルを編集すればコンテナ内のファイルも同時に編集できる。
しかしながら、コンテナをわざわざ立てている時は、プログラムの実行環境がコンテナ内に構築されていることがほとんどのため、このやり方ではデバッグが非常に難しい。

以前、VSCodeのRemoteDevelopment をつかって、ローカルのコンテナ内のファイルを直接編集するやり方について記事を書いた(https://qiita.com/kenmaro/items/e23637bdb00d28e1fef6)
が、今回はリモートサーバー上のコンテナ内のファイルをローカルのVSCodeからリモート編集するやり方を解説する。

状況説明

リモートサーバはUbuntu想定。リモートサーバ上のコンテナもUbuntu想定です。
1. 自分はPCを使って(家などからリモートで)作業しており、(例えば会社内とかの)サーバーにSSHでログインしたい。
2. そのとき、リモートサーバ上でいつも開発のために使用しているDockerコンテナがある。
3. そのDockerコンテナに直接自分のPCのVSCodeからリモートログインしたい。

簡単な流れ

  1. リモート上のコンテナは、リモートサーバの任意のポートが、コンテナの22番にマッピングされている。
  2. ssh-keygen を使って、sshするために必要な公開鍵、秘密鍵を作成する。
  3. 公開鍵を、リモートサーバと、リモートサーバ上のDockerコンテナ上に置く。
  4. 公開鍵のパーミッションを設定する。
  5. リモートサーバおよびコンテナ内でssh serverを設定する。
  6. ローカルPCのSSH configファイルを編集し、リモートサーバおよびコンテナにsshできることを確かめる。
  7. VSCodeのRemoteDevelopmentを使って、リモートサーバ上のコンテナ内のファイルを、コンテナ内にsshして直接編集できることを確かめる。

という流れになります。めんどくさいように見えますが、流れに従えば多分10分くらいでできます!!

0. リモート上のコンテナは、リモートサーバの任意のポートが、コンテナの22番にマッピングされている。

これは、Docker コンテナをリモートサーバに作る際に、
docker run -p 10000:22
のようにして、リモートのポート(ここでは10000)をコンテナ内の22番ポートにマッピングしときます。

1. ssh-keygen を使って、sshするために必要な公開鍵、秘密鍵を作成する。

これに関してはたくさんググれば出てくるので、
https://qiita.com/suthio/items/2760e4cff0e185fe2db9
http://gomocool.net/gomokulog/?p=557
https://webkaru.net/linux/ssh-keygen-command/
などにしたがってローカルPC上に、ssh用の公開鍵と秘密鍵を生成してください。このとき、使う鍵長に気をつけましょう!!

2. 公開鍵を、リモートサーバと、リモートサーバ上のDockerコンテナ上に置く。

公開鍵はなんらかの方法でログインしたいリモートサーバ、およびコンテナ内の ~/.ssh/authorized_keys に保存します。authorized_keysはファイル名。~/.sshというフォルダがない時は、作りましょう。

3. 公開鍵のパーミッションを設定する。

リモートサーバ、およびコンテナ内で先ほど作った~/.ssh/authorized_keysのパーミッションを設定します。コマンドは、
chmod 600 ~/.ssh/authorized_keys
です。

4. リモートサーバおよびコンテナ内でssh serverを設定する。

リモートサーバ、およびコンテナ内で、
apt-get install -y openssh-server を実行。

そのあと、リモートサーバ上で、sshしたいユーザ名(この場合はroot、適宜変更してください。)に応じてsshパスワードを以下のコマンドで決めます。Dockerコンテナで何もユーザー登録していない時は、rootでも良いと思います。
echo 'root:あなたが決めるパスワード' | chpasswd

その後、リモートサーバ上と、コンテナ上で以下のコマンドによりパスワードによるログインを許可。
sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

5. ローカルPCのSSH configファイルを編集し、リモートサーバおよびコンテナにsshできることを確かめる。

ローカルPCの、~/.ssh/configファイルを編集します。ない時は作りましょう。以下が例になります。

Host myRemoteServer
  IdentityFile    ~/.ssh/id_rsa
  IdentitiesOnly  yes
  Hostname 192.168.100.20
  User username
  LocalForward 23750 /var/run/docker.sock

Host myRemoteDockerContainer
    IdentityFile ~/.ssh/id_rsa
    IdentitiesOnly yes
    HostName 127.0.0.1
    User root
    Port 10000
    ProxyCommand ssh -W %h:%p myRemoteServer

1つ目の、myRemoteServerに関して、
- ssh host は Hostname。
- ssh したいユーザは User。
- IdentityFile は作成した秘密鍵へのパス。(もちろん秘密鍵はローカル側にあるのでローカルのパスです。)

2つ目の myRemoteDockerContainerに関して、基本的に同じですが、

  • ProxyCommand ssh -W %h:%p myRemoteServerにより、myRemoteServerのポート10000 にアクセスという意味。0での手順により、これはコンテナ内の22番ポートにマッピングされる、すなわちコンテナ内にSSHアクセスできる。

ここで、ローカルPCのターミナルから、
ssh myRemoteServer`

とすると リモートサーバに無事ログインでき、
ssh myRemoteDockerContainer

とすると リモートサーバ上のコンテナに無事ログインできることを確かめてください。

6. VSCodeのRemoteDevelopmentを使って、リモートサーバ上のコンテナ内のファイルを、コンテナ内にsshして直接編集できることを確かめる。

ここまでくればもうできたも同然です。ローカルPCでVSCodeを開き、エクステンションのRemote Developmentをインストールします。
インストールすると、ウィンドウの一番左下に、緑のボタンができるので、クリック。
Screen Shot 2020-03-05 at 0.19.13.png

そして、Remote-SSH: Connect to Host をクリック。
Screen Shot 2020-03-05 at 0.19.45.png

さらに、さきほどconfigファイルに書いた、myRemoteDockerContainer を選択し、
echo 'root:あなたが決めるパスワード' | chpasswd でコンテナサイドで設定したパスワードを入力すると、、、、、

Screen Shot 2020-03-05 at 0.23.17.png

無事、VSCodeからリモート内のコンテナに直接アクセスできるはずです。

まとめ

すばらしい、マイクロソフト先生すばらしい、、、!!!

おわり

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