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

AzureAppServiceでDockerを使ってWebアプリを公開する

概要

試しに利用してみたら便利だったので、記録として残します。
ただ、個人的にはVPC内に置く機能がβ版だったり、Webアプリとしてしか公開ができなかったり、
本番運用としてはログ周りの機能が弱いとも感じるので趣味サイトとして利用することを前提とした方がいいと思います。

仕様等

AzureAppServiceを利用するにはAppServicePlanとAppServiceを作成する必要があります。
例えるとAppServicePlanがサーバであり、AppService自体はアプリケーションを管理する物という感じ。

Azure CLIのインストール

$ brew install azure-cli

Windwosの場合はこちらをご覧ください

azコマンドのリファレンス

構築手順

RailsのWelcome画面を出すまでところまでとします。

  1. Azure環境にログイン
  2. ResourceGroupの作成
  3. AzureContainerRegistry(以下ACR)の作成
  4. RailsのDockerImageの準備
  5. ACRにDockerImageのPush
  6. AppServicePlanの作成
  7. AppServiceの作成
  8. CDの設定
  9. 環境変数の設定
  10. 確認

1. Azure環境にログイン

ブラウザでログイン画面が表示されるのでログインする

$ az login

2. ResourceGroupの作成

これに各種リソースを登録していきます

$ az group create --name nagi125-dev --location japaneast

3. AzureContainerRegistryの作成

これにDockerImageを登録していきます

$ az acr create --resource-group nagi125-dev --name nagi125acr --sku Basic --admin-enabled true --location japaneast

4. RailsのDockerImageの準備

Railsアプリケーションの作成

$ rails new rails-sample-app
$ cd ./rails-sample-app
$ touch Dockerfile
$ vim Dockerfile

Dockerfileの準備

FROM ruby:2.6.3

ENV TZ Asia/Tokyo
ENV RAILS_ENV development

RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y netcat build-essential libpq-dev nodejs && \
    apt-get clean && \
    rm -rf /var/cache/apt
RUN gem install bundler

COPY Gemfile Gemfile.lock /app/

WORKDIR /app
RUN bundle install

COPY . /app

ENTRYPOINT ["rails", "server", "-b", "0.0.0.0"]

Imageの作成とACR用のタグをつける

$ docker build -t nagi125/rails-sample-app .
$ docker tag nagi125/rails-sample-app:latest nagi125acr.azurecr.io/nagi125/rails-sample-app:latest

5. ACRにDockerImageのPush

$ az acr login --name nagi125acr
$ docker push nagi125acr.azurecr.io/nagi125/rails-sample-app:latest

6. AppServicePlanの作成

$ az appservice plan create --resource-group nagi125-dev --name rails-sample-app-plan --sku B1 --location japaneast --is-linux

7. AppServiceの作成

AppServicePlanとACRのImageを指定して作成する

$ az webapp create --resource-group nagi125-dev --plan rails-sample-app-plan --name rails-sample-app --deployment-container-image-name nagi125acr.azurecr.io/nagi125/rails-sample-app:latest

8. CD設定

これを設定する事でImageをPushしてしばらくするとAppServiceに反映されるようになります。
※ 2-3分経っても反映されない場合AppServiceの再起動をしてみるとよいかも。

AppServiceとACRの紐付け

$ az webapp config container set --name rails-sample-app --resource-group nagi125-dev --docker-custom-image-name nagi125acr.azurecr.io/nagi125/rails-sample-app:latest --docker-registry-server-url http://nagi125acr.azurecr.io --docker-registry-server-user nagi125acr --docker-registry-server-password xxxxx

※ passwordはコマンドから確認できないため下記手順で確認する
nagi125acr_-_アクセス_キー_-_Microsoft_Azure.png

CD設定

webhookのuriは返ってきた値を利用する
※ zsh等を利用している人は$のエスケープを忘れないようにしてください

$ az webapp deployment container config -g nagi125-dev -n rails-sample-app --enable-cd true
$ az acr webhook create -n railsSampleApp -r nagi125acr --scope nagi125/rails-sample-app:latest --location japaneast --uri xxxxx --actions push delete

9. 環境変数の設定

$ az webapp config appsettings set --settings RAILS_ENV=development -g nagi125-dev -n rails-sample-app

10. 確認

$ az webapp browse --resource-group nagi125-dev --name rails-sample-app

ブラウザに例の画面が表示されれば成功です。
※ 初回だと反映までに5分ぐらいかかるかもしれません。
Ruby_on_Rails.png

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

AzureAppServiceでContainerを使ってWebアプリを公開する

概要

試しに利用してみたら便利だったので、記録として残します。
ただ、個人的にはVPC内に置く機能がβ版だったり、Webアプリとしてしか公開ができなかったり、
本番運用としてはログ周りの機能が弱いとも感じるので趣味サイトとして利用することを前提とした方がいいと思います。

仕様等

AzureAppServiceを利用するにはAppServicePlanとAppServiceを作成する必要があります。
例えるとAppServicePlanがサーバであり、AppService自体はアプリケーションを管理する物という感じ。

Azure CLIのインストール

$ brew install azure-cli

Windwosの場合はこちらをご覧ください

azコマンドのリファレンス

構築手順

RailsのWelcome画面を出すまでところまでとします。

  1. Azure環境にログイン
  2. ResourceGroupの作成
  3. AzureContainerRegistry(以下ACR)の作成
  4. RailsのDockerImageの準備
  5. ACRにDockerImageのPush
  6. AppServicePlanの作成
  7. AppServiceの作成
  8. CDの設定
  9. 環境変数の設定
  10. 確認

1. Azure環境にログイン

ブラウザでログイン画面が表示されるのでログインする

$ az login

2. ResourceGroupの作成

これに各種リソースを登録していきます

$ az group create --name nagi125-dev --location japaneast

3. AzureContainerRegistryの作成

これにDockerImageを登録していきます

$ az acr create --resource-group nagi125-dev --name nagi125acr --sku Basic --admin-enabled true --location japaneast

4. RailsのDockerImageの準備

Railsアプリケーションの作成

$ rails new rails-sample-app
$ cd ./rails-sample-app
$ touch Dockerfile
$ vim Dockerfile

Dockerfileの準備

FROM ruby:2.6.3

ENV TZ Asia/Tokyo
ENV RAILS_ENV development

RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y netcat build-essential libpq-dev nodejs && \
    apt-get clean && \
    rm -rf /var/cache/apt
RUN gem install bundler

COPY Gemfile Gemfile.lock /app/

WORKDIR /app
RUN bundle install

COPY . /app

ENTRYPOINT ["rails", "server", "-b", "0.0.0.0"]

Imageの作成とACR用のタグをつける

$ docker build -t nagi125/rails-sample-app .
$ docker tag nagi125/rails-sample-app:latest nagi125acr.azurecr.io/nagi125/rails-sample-app:latest

5. ACRにDockerImageのPush

$ az acr login --name nagi125acr
$ docker push nagi125acr.azurecr.io/nagi125/rails-sample-app:latest

6. AppServicePlanの作成

$ az appservice plan create --resource-group nagi125-dev --name rails-sample-app-plan --sku B1 --location japaneast --is-linux

7. AppServiceの作成

AppServicePlanとACRのImageを指定して作成する

$ az webapp create --resource-group nagi125-dev --plan rails-sample-app-plan --name rails-sample-app --deployment-container-image-name nagi125acr.azurecr.io/nagi125/rails-sample-app:latest

8. CD設定

これを設定する事でImageをPushしてしばらくするとAppServiceに反映されるようになります。
※ 2-3分経っても反映されない場合AppServiceの再起動をしてみるとよいかも。

AppServiceとACRの紐付け

$ az webapp config container set --name rails-sample-app --resource-group nagi125-dev --docker-custom-image-name nagi125acr.azurecr.io/nagi125/rails-sample-app:latest --docker-registry-server-url http://nagi125acr.azurecr.io --docker-registry-server-user nagi125acr --docker-registry-server-password xxxxx

※ passwordはコマンドから確認できないため下記手順で確認する
nagi125acr_-_アクセス_キー_-_Microsoft_Azure.png

CD設定

webhookのuriは返ってきた値を利用する
※ zsh等を利用している人は$のエスケープを忘れないようにしてください

$ az webapp deployment container config -g nagi125-dev -n rails-sample-app --enable-cd true
$ az acr webhook create -n railsSampleApp -r nagi125acr --scope nagi125/rails-sample-app:latest --location japaneast --uri xxxxx --actions push delete

9. 環境変数の設定

$ az webapp config appsettings set --settings RAILS_ENV=development -g nagi125-dev -n rails-sample-app

10. 確認

$ az webapp browse --resource-group nagi125-dev --name rails-sample-app

ブラウザに例の画面が表示されれば成功です。
※ 初回だと反映までに5分ぐらいかかるかもしれません。
Ruby_on_Rails.png

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

DockerでFlask開発環境構築

使うもの

  • macOS High Sierra
  • Docker
  • VSCode
  • brew

VSCodeの設定

まずはVSCodeにPythonの拡張機能をインストールします。

すると以下の警告が出ています。
スクリーンショット 2019-08-18 12.27.51.png

macに入っているデフォルトのPython2は推奨されないみたいなので、python3をインストールします。
brew install python3

「Select Python Interpreter」を押してPython3を設定。

あとは以下の警告も消すために「install」を押してpipもインストールしておきます。

スクリーンショット 2019-08-18 12.37.53.png

pip3 --versionでバージョン情報が出てばインストール完了。

VSCodeの設定はここで完了。

Dockerの設定

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

root
├── Dockerfile
├── docker-compose.yml
└── main.py

それぞれのファイルは以下の通り

Dockerfile
FROM python:3.7

WORKDIR /app

RUN pip install flask
RUN pip install xmltodict

CMD [ "python", "main.py" ]
docker-compose.yml
version: '3'
services:
  api:
    build: .
    ports:
      - 80:8080
    volumes:
      - ./main.py:/app/main.py
    tty: true
main.py
from flask import Flask, jsonify, request
import json
import urllib.request
import xmltodict

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False

@app.route("/", methods=['GET'])
def index():
    # パラメーター取得
    keyword = request.args.get('keyword')
    # API通信
    req = "https://news.google.com/rss/search?q=" + urllib.parse.quote_plus(keyword, encoding='utf-8') + "&hl=ja&gl=JP&ceid=JP:ja"
    # 結果取得
    with urllib.request.urlopen(req) as res:
        body = res.read()
    # XML → 辞書に変換
    dict = xmltodict.parse(body)
    # 辞書 → JSONに変換
    data = json.dumps(dict, indent=4, ensure_ascii=False)
    # 結果返却
    return data

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

keywordパラメータで受け取った文字列でGoogleNewsのRSS取得してJSON形式で返すだけのAPIです。

動作確認

docker-compose up -dでコンテナ起動

あとはこんな感じでAPI叩いて結果返ってくれば終わり
http://localhost?keyword=スマホ

以上。サクッとFlask環境構築でした。

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

docker上のmysqlのデータバックアップ

バックアップ

docker exec {container_name} /usr/bin/mysqldump -uroot -ppassword {database_name} > backup.sql

復元

cat backup.sql | docker exec -i {container_name} /usr/bin/mysql -uroot -ppassword {database_name}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Batchでのマルチスレッド処理では、コンテナあたりのスレッド数に要注意

AWS Batchでのマルチスレッド処理では、コンテナあたりのスレッド数に要注意

AWS Batchのジョブ設定には、VCPUという項目がある。
設定の名称からすると、コンテナ内から見えるCPU数が変わるのではないか?という期待を持ってしまう。

しかし、この設定の実態はただの優先度設定である (docker runの--cpu-sharesオプションにマップされている)。
ここに何を設定したとしても、コンテナ内からは、Dockerホストに実装されているCPUコアが全て見えてしまう。

何が問題になるか

ミスの例

OpenMPなどの並列化プラットフォームを利用すると、デフォルトでは、システムに実装されているCPU数分のスレッドが起動する動作になっていることが多い。
そのような動作をするプログラムを動かす際、以下のような(間違った)設定をしたとする。

  • ジョブ定義:

    VCPU=2、メモリ8GiB

    ※「全スレッド共有で4GiB使用し、さらに1スレッドごとに2GiBのメモリを使用する」という設計のプログラムを動かすものとする。
    ※2スレッド動作時は、4 + 2 * 2で8GiB必要となる。

  • コンピューティング環境:

    m4.16xlarge (32物理コア・ 256 GiBメモリ)

設定時の想定では、16コンテナで32スレッドが起動し、16 * 8 = 128GiBのメモリが消費される。
しかしこの場合、実際には、16コンテナ * 32スレッド(物理コア数分) = 512スレッドが起動する。

発生する問題

  • 事故パターン1 OOM

    512スレッド * 2GiBだけでも1TiBのメモリが必要になるが、動作しているEC2インスタンスには256GiBしか実装されていない。
    そこで、OOM Killerさんが目覚める。

    _人人人人人人_
    > 突然の死 <
     ̄Y^Y^Y^Y^Y^Y^ ̄

  • 事故パターン2 性能劣化

    スレッドごとに必要なメモリが少なく、OOMが起きなかったとする。
    それでも、処理の大半が演算の場合、CPUの奪い合い(コンテキストスイッチ祭り)が発生する。

    _人人人人人人人_
    > 無駄に遅い <
     ̄Y^Y^Y^Y^Y^Y^Y^ ̄

    ただし、この動作は、インスタンスに対して起動中のコンテナが少ない場合にはメリットとなるので、一長一短。
    コンテナがCPU性能を目いっぱい使うので処理がすぐ終わり、ジョブが無くなったインスタンスがスケールインすることでコストが下がる。
    大抵の場合はメリットのほうが大きいかも。

どうすりゃいいのか

  • スレッド数に比例して消費メモリが(大きく)増える設計/実装は避ける

  • 上記が無理なら、起動するスレッド数を固定する

    ハードコードではなく、環境変数経由で指定できるようにして、ジョブ定義で調整するとベター。
    OpenMPならデフォルトでOMP_NUM_THREADS環境変数によるスレッド数指定に対応している。

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

macOSでDockerコマンドの入力補完を有効化する手順

1. bash-completionをインストールする

bash
$ brew install bash-completion

2. .bashrc.bash_profileに以下の内容を追加する

.bashrc
if [ -f `brew --prefix`/etc/bash_completion ]; then
    . `brew --prefix`/etc/bash_completion
fi
.bash_profile
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

3. Dockerのシンボリックリンクを追加する

bash
$ ln -s /Applications/Docker.app/Contents/Resources/etc/docker.bash-completion /usr/local/etc/bash_completion.d/docker
$ ln -s /Applications/Docker.app/Contents/Resources/etc/docker-machine.bash-completion /usr/local/etc/bash_completion.d/docker-machine
$ ln -s /Applications/Docker.app/Contents/Resources/etc/docker-compose.bash-completion /usr/local/etc/bash_completion.d/docker-compose

参考文献

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

MacでDockerコマンドの入力補完を有効化する手順

1. bash-completionをインストールする.

bash
$ brew install bash-completion

2. .bashrc.bash_profileに以下の内容を追加する.

.bashrc
if [ -f `brew --prefix`/etc/bash_completion ]; then
    . `brew --prefix`/etc/bash_completion
fi
.bash_profile
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

3. Dockerのシンボリックリンクを追加する.

bash
$ ln -s /Applications/Docker.app/Contents/Resources/etc/docker.bash-completion /usr/local/etc/bash_completion.d/docker
$ ln -s /Applications/Docker.app/Contents/Resources/etc/docker-machine.bash-completion /usr/local/etc/bash_completion.d/docker-machine
$ ln -s /Applications/Docker.app/Contents/Resources/etc/docker-compose.bash-completion /usr/local/etc/bash_completion.d/docker-compose

参考文献

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

[2019-08-19] Ubuntu 18.04+Docker(19.03)+NVIDIA GPU環境セットアップ

やり方がまた変わっていたのでメモしておきます。

$ grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Ubuntu 18.04.3 LTS"

(標準で入るドライバを無効化する作業がまず必要かもしれない)

Dockerのインストール

https://docs.docker.com/install/linux/docker-ce/ubuntu/
にしたがってやる。

$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
$ 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-get install docker-ce docker-ce-cli containerd.io
$ docker -v
Docker version 19.03.1, build 74b1e89

https://docs.docker.com/install/linux/linux-postinstall/
にしたがってやる。

$ sudo usermod -aG docker $USER
(logout -> login)
$ docker run hello-world
Hello from Docker!
...

NVIDIAドライバ

$ lspci | grep NVIDIA
00:09.0 VGA compatible controller: NVIDIA Corporation GP102 [GeForce GTX 1080 Ti] (rev a1)

$ sudo apt install nvidia-headless-430 nvidia-utils-430

DockerのNVIDIA対応のためのパッケージ

https://github.com/NVIDIA/nvidia-docker
にしたがってやる。

$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

$ sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit

確認

$ sudo reboot

$ nvidia-smi
...
| NVIDIA-SMI 430.26       Driver Version: 430.26       CUDA Version: 10.2     |
...

$ docker run --gpus all --rm nvidia/cuda nvidia-smi
...
| NVIDIA-SMI 430.26       Driver Version: 430.26       CUDA Version: 10.2     |
...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vagrant+VirtualBoxによるDocker環境構築

はじめに

これまで.NETの開発をメインでやってきて、一昨年からPHPのプロジェクトに参画した。
それまで VM Wareを使っていたとは言え、普段意識しないし、コンテナとかも使ったことが無かったが、
PHPのプロジェクトではVagrantやDockerなど(自分的には)最新技術に触れて衝撃を受けた。

今更ながら勉強する為、まずはPythonの開発環境をDockerで用意しようと考えたが、
Winodws 7 な環境しか手元にない。

Dockerは、LinuxもしくはWindowsではWindows 10 からしか使えないので、
Vagrant+VirtualBoxで用意した仮想環境(CentOS)へDockerを載せて環境を用意してみます。

Vagrant

VirtualBox

  • 現在利用しているOS(Windows7)上で、別のOS(今回はCentOS)を実行できる仮想化ソフトウェア。
  • 現在利用しているOS(Windows7)をホストOS、VirtualBox上に構築したOS(CentOS)をゲストOSと呼ぶ。
  • ホストOSでは導入できないソフトウェア(今回はdocker)を利用したい場合や、開発チーム全体で開発環境を統一したい場合、もしくは単にホストOSを汚したく無い場合にも利用する。
  • https://ja.wikipedia.org/wiki/VirtualBox

今回の構築環境

  • Vagrant+VirtualBoxで、CentOSを載せて、そこでDockerを動作させコンテナを起動します。
  • イメージは↓こんな感じ。

kankyo.png

用語の定義

ホストとかゲストとかが分かりにくいと思うので、この後の文章では以下のように用語を使います。

Windows 7 VirtualBox内のCentOS CentOS内のDockerコンテナ
ホスト ゲスト 又は Dockerホスト Dockerコンテナ

インストール

全て仮想環境上で環境構築する為、基本的にWindows7環境は汚れませんが、
VagrantとVirtualBoxだけはインストールする必要があります。

環境構築(仮想環境構築)

コマンドプロンプトを起動し、適当なフォルダへ移動します。

> d:
> cd d:\work

CentOSのイメージをダウンロードします。(これ、結構かかります)

> vagrant box add centos/7

CentOS起動用のVagrantfileの雛形を作成します。

> vagrant init centos/7

作成したVagrantfileの雛形をカスタマイズします。
D:\work フォルダに Vagrantfileファイルが出来ているので、テキストエディタで開いて、以下の編集を行います。
以下の行のコメントアウトを解除するだけです。

Vagrantfile
35|  config.vm.network "forwarded_port", guest: 80, host: 8080
  • 35行目の編集はホストOSとゲストOS間のポートマッピング設定です。後でホストOSのブラウザからコンテナ上のWebAppへアクセスする為に必要です。

さあ、Vagrantを起動しましょう。

> vagrant up

カレントフォルダのvagrantfileを参照して、そこに記載してある仮想環境を構築、起動します。

恐らくこれで、仮想環境(CentOS)が起動しているので、仮想環境にSSHで接続しましょう。

> vagrant ssh

環境構築(コンテナ環境構築)

ここからはDockerコンテナを利用する為の準備をしていきます。

Dockerを利用するのに必要なパッケージ(yum-utils, device-mapper-persistent-data, lvm2)をインストールします。

$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2

Dockerをダウンロードするリポジトリをyum(パッケージ管理)に追加します。

$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

yumのパッケージインデックスを更新(DockerのINSTALLやUPGRADEの前に一回実行することが推奨されている)

$ sudo yum makecache fast

最新版のDockerをインストールします。

$ sudo yum install docker-ce

Dockerデーモンを起動します。

$ sudo systemctl start docker

Dockerコンテナ動作確認

これでDockerの起動まではできました。
(DockerイメージからDockerコンテナを作り出して起動する為のソフトウェアが動きました)
Dockerの動作確認の為、DockerイメージからDockerコンテナを起動して動作確認をしてみます。

ここでは、training/webappというWebアプリケーション動作確認用コンテナを持ってきて起動してみます。
(やっぱりブラウザとかで動いているのが見えるのがいいよね)

$ sudo docker run -d -p 80:5000 training/webapp python app.py
  • -dオプションはバックグランド実行用のオプションです。これが無いと、「training/webapp」が終わるまで他のコマンドが打てません。
  • -pオプションはポートマッピングです。vagrantfileでホストOSとゲストOS間で8080→80でマッピングしたポートを、さらに80→5000にマッピングします。
  • 「python app.py」は「training/webapp」コンテナ内で実行するコマンドです。(とりあえずおまじないだと思って入力)

「training/webapp」イメージは350MBくらいあるので、少しダウンロードに時間がかかります。
動作確認はホストOS(Windows7)のブラウザで以下のURLを指定してください。

http://localhost:8080/

以下のように出てくればOKです。

a.png

ホストOSとゲストOS間のポートマッピングはvagrantfileで 8080→80 で設定されており、
上記のdocker runコマンドで -p を指定して、ゲストOSとdockerコンテナ間のポートマッピングを 80→5000 で設定しています。

その為、ホスト側でのポート指定は8080になります。

コンテナの停止、他

Dockerコンテナを確認します。

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                  NAMES
1c763df10ac5        6fae60ef3446        "python app.py"     About a minute ago   Up About a minute   0.0.0.0:80->5000/tcp   frosty_wing

起動しているDockerコンテナをコンテナID(ここでは、1c763df10ac5)を指定して、停止します。

$ sudo docker stop 1c763df10ac5

停止されたか確認しましょう。(先ほどまで表示されていたコンテナ(1c763df10ac5)が消えています)

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                  NAMES

起動しているコンテナは無くなりましたが、コンテナ自体は残っていて、-aオプションで全てのコンテナが表示できます。

$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                       PORTS               NAMES
1c763df10ac5        6fae60ef3446        "python app.py"     8 minutes ago       Exited (137) 3 minutes ago                       frosty_wing

このコンテナも削除してみましょう。
コンテナの削除は docker rm です。

$ sudo docker rm 1c763df10ac5
$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                       PORTS               NAMES

これでコンテナは消えましたが、イメージは残っています。

$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
training/webapp     latest              6fae60ef3446        4 years ago         349MB

折角なので、イメージも削除しましょう。
イメージの削除は docker rmi です。

$ sudo docker rmi 6fae60ef3446
Untagged: training/webapp:latest
Untagged: training/webapp@sha256:06e9c1983bd6d5db5fba376ccd63bfa529e8d02f23d5079b8f74a616308fb11d
Deleted: sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557
Deleted: sha256:875bde2b9e2d99e7c1362993645a474fe621475c6fc1b1623c9ed5312b7bdeae
Deleted: sha256:bbdb5ee3757ef8f2633694016df5840fc3410422b37c22f98c0300e295ce75cc
Deleted: sha256:d718446240e3f48a904ad4bbf2a1f61737c5d70df35b8210d674a9517cdc9803
Deleted: sha256:a890440f4933412f9aafb056eb2f07f2276ed756631a81e960d4a8a6de5857a3
Deleted: sha256:68a74799a9e67953725058ef21a530f100025088943446aa60c73fba7beebd47
Deleted: sha256:b23e4b6b440d0e9ab4ffd7852fbf81edd6d5eb606e24d4950d83502e14af2856
Deleted: sha256:f115b0453c71fb4d21fdb6f579201984bd5033ae28ed5908978576a19282418b
Deleted: sha256:b0da82df3229cd06a2992449f2310caaa42f09fdfb088f4a98c5ea587ea85c7e
Deleted: sha256:f6f162dad6e64715d3d07e21d4574733860a557f2f89228d07909c1f6f04e882
Deleted: sha256:088f9eb16f16713e449903f7edb4016084de8234d73a45b1882cf29b1f753a5a
Deleted: sha256:799115b9fdd1511e8af8a8a3c8b450d81aa842bbf3c9f88e9126d264b232c598
Deleted: sha256:3549adbf614379d5c33ef0c5c6486a0d3f577ba3341f573be91b4ba1d8c60ce4
Deleted: sha256:1154ba695078d29ea6c4e1adb55c463959cd77509adf09710e2315827d66271a
$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

バイバイ

コンテナを抜けます。

$ exit

仮想マシン(centos)を停止します。

> vagrant halt
==> default: Attempting graceful shutdown of VM...

仮想マシンの一覧は以下のコマンドで確認できます。

> vagrant box list
centos/7       (virtualbox, 1905.1)

おわりに

とりあえず、Vagrant+VirtualBox上のCentOSでDockerコンテナを起動するところまでできました。

当初は仮想環境とDockerイメージとDockerコンテナがゴチャゴチャになっていましたが、
実際に手を動かして環境を作っていくと、理解が深まりました。

参考

https://www.tohuandkonsome.site/entry/2018/03/21/193730
https://qiita.com/inakadegaebal/items/be9fecce813cebec5986

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

Vue.js & Django を Docker と組み合わせてSPA+APIサーバー環境をつくる

はじめに

今回は、Django REST Frameworkを使った、
Vue.jsをSPAとして運用できる環境の作り方をシェアできればと思います。

Docker Composeを使うので、本番で使うときはGKEなどの
モダンなコンテナ型オーケストレーションツールを選択可能かつ、開発でも
メンバーの増員などに柔軟に対応できる環境を作れたらと思います。

今回は抜粋で書いているので、
不足等ございましたら、ご連絡よろしくお願いいたします。

構成

構成は下記のような形にします。
本来だと下記に+DBもあるような構成が基本ですが、
コンテナ上で動かす場合と、クラウドのDBサービスを使用する場合など
多岐の選択があるため、今回はなしとします。

サーバー構成

サーバー名 名称 ポート番号
開発サーバー(Vue.js) front 8080
APIサーバー(Django) back 8001
Webサーバー(Nginx) web 8000

Docker Compose ファイルで骨組みを作る

最初にdocker-compose.ymlファイルと各種サーバーのDockerfileを作成して、
骨組みを形作っていきます。

1. docker-compose.ymlを作成

注意点としては、バックエンド側のstaticファイルをnginxに置いて
配信可能とする点です。
今回はAPIサーバーとしての使用のため、不要と思われますが、
djangoのデバッグ画面(管理画面など)を表示する際に使用できるので、
volumesにて、同期します。
基本的に起動は、拡張していくことも考えて、
Shellファイルに落とし込んでいきます。
(直で記載でも良いとは思います。)

docker-compose.yml
version: '3'

services:

  web:
    build:
      context: ./
      dockerfile: ./web/Dockerfile
    environment:
      TZ: 'Asia/Tokyo'
    ports:
      - 8000:8000
    volumes:
      - ./web/logs/nginx/:/var/log/nginx/
      - ./web/uwsgi_params:/etc/nginx/uwsgi_params
      - ./back/static:/var/www/static/
    depends_on:
      - back

  back:
    build:
      context: ./back
      dockerfile: Dockerfile
    command: 'sh /server/start.sh'
    expose:
      - "8001"
    volumes:
      - ./back:/server/

  front:
    build:
      context: ./front
    command: 'sh /app/start.sh'
    volumes:
      - ./front:/app/:cached
      - ./front/node_modules:/app/node_modules
    ports:
      - "8080:8080"

2. DockerFile フロントエンド側を作成

npmを使用するために、nodeイメージを入れます。
後ほど立ち上げるためにコメントアウトなども挟むので、
一旦スキップしても構いません。

Dockerfile(フロントエンド)
FROM node:10.7.0

WORKDIR /app
RUN npm install -g @vue/cli
ADD ./package.json /app/package.json
RUN npm install
ADD ./start.sh /app/start.sh

3. DockerFile バックエンド側を作成

バックエンド側をゴリゴリ書いていきます。
ライブラリのインストールも都度できるように
requirements.txt経由でインストールします。

Dockerfile(バックエンド)
FROM python:3.7
ENV PYTHONUNBUFFERED 1

WORKDIR /server
ADD . /server/
RUN pip install --upgrade pip
RUN pip install -r requirements.txt

4. DockerFile Webサーバー側を作成

設定ファイル、Vue.jsで作成しビルドしたものを格納します。
バージョンはお好みのものをご使用ください。

Dockerfile(Webサーバー)
FROM nginx:1.11.7

# 設定ファイル
ADD ./web/nginx.conf /etc/nginx/nginx.conf
ADD ./web/default.conf /etc/nginx/sites-available/default
ADD ./web/default.conf /etc/nginx/sites-enabled/default
ADD ./web/uwsgi_params /etc/nginx/uwsgi_params

RUN mkdir /var/www
RUN mkdir /var/www/front
RUN mkdir /var/www/static

ここまで作成するとある程度骨組み部分は出来上がった状態になります。
ここから、実際にサーバーとして使用できるように
各サーバー内に手を加えて初期構築をしていきます。

フロントエンド側を作成

Vue.jsを使えるようにVue CLIを導入して、
使用できる状態にしていきます。
エラーを防ぐために一旦Dockerfileで書いた下記をコメントアウトします

FROM node:10.7.0

WORKDIR /app
RUN npm install -g @vue/cli
# ADD ./package.json /app/package.json
# RUN npm install
# ADD ./start.sh /app/start.sh

Vue CLIを入れることで、Vueの開発環境を簡単に作成することができます。
早速Terminalからプロジェクトを作成し、開発サーバーとして立ち上げてみましょう。
各種設定方法を聞かれますが、enterで進んでいくとデフォルトのものがインストールされます。

ターミナル
// hoge-projectにはプロジェクト名を入力してください。
$ docker-compose run front vue create hoge-project

先ほどDockerfileに入力したコメントアウトを外して、
start.shを軽く記載した後、立ち上げてみましょう。
(プロジェクト先に向き先を当てるため、ファイルの向き先も変更するか、
 プロジェクトフォルダを移動して、動くか確認してみてください。)

start.sh
npm run serve
ターミナル
$ docker-compose build front
$ docker-compose up -d front

ローカルホストで確認すると無事立ち上がっているかと思います。

バックエンド側を作成

次にDjango側を作成していきます。
ターミナルからDjangoアプリの初期作成コマンドを打ちます。

ターミナル
$ docker-compose exec back django-admin startproject mysite

次にアプリケーションを作成します。
最後の確認の際に使います。

ターミナル
$ docker-compose exec back python mysite/manage.py startapp testapi

起動用のシェルも書いておきます。

start.sh
#!/bin/bash
sleep 5
python manage.py makemigrations
python manage.py migrate
python manage.py collectstatic --noinput
uwsgi --socket :8001 --module mysite.wsgi

Django REST Frameworkを使用するので
インストールする設定ファイルに記載します。

requirements.txt
django>=2.1.10
uwsgi==2.0.17.1
djangorestframework==3.8.2

一旦ここまでで、最後に疎通確認するので、
次に進みます。

Webサーバーを立てる

nginx.conf, default.conf, uwsgi_paramsなどの
設定ファイルを作成していきます。

1. nginx.conf

nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
daemon off;

events {
    worker_connections 65535;
    multi_accept on;
    use epoll;
}

http {

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    types_hash_max_size 2048;
    client_max_body_size 20M;
    keepalive_timeout     3600;
    proxy_connect_timeout 3600;
    proxy_send_timeout    3600;
    proxy_read_timeout    3600;
    send_timeout          3600;
    client_body_timeout   300;

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

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

    access_log /dev/stdout with_time;
    error_log stderr;

    gzip on;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

    limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
    limit_req_status 429;
}

2. default.conf

default.conf
# development
upstream webserver {
  ip_hash;
  server back:8001;
}

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

server {
  listen 8000;
  server_name 127.0.0.1;

  client_header_buffer_size 1k;
  large_client_header_buffers 8 32k;

  add_header Strict-Transport-Security 'max-age=31536000';
  add_header X-Frame-Options DENY;
  add_header X-XSS-Protection "1; mode=block";

  error_page 500 502 503 504 /50x.html;

  # フロントエンド
  location / {
    root /var/www/front;
    try_files $uri $uri/ /index.html;
  }

  # バックエンドサーバー 静的ファイル群
  location /static {
    alias /var/www/static;
  }

  # バックエンドサーバー
  location /back/ {
    include /etc/nginx/uwsgi_params;
    uwsgi_pass webserver;
    proxy_redirect     off;
    proxy_set_header   Host $host;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Host $server_name;
    proxy_read_timeout 86400s;
    proxy_send_timeout 86400s;
  }

  # バックエンド adminサーバー
  location /admin/ {
    include /etc/nginx/uwsgi_params;
    uwsgi_pass webserver;
    proxy_redirect     off;
    proxy_set_header   Host $host;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Host $server_name;
  }

  location = /50x.html {
    root /usr/share/nginx/html;
  }
}

3. uwsgi_params

uwsgi_params
uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

問題ないかテスト

試しにVue.js側でAxiosを導入して、
リクエストを送ってみて、きちんとAPIサーバーから値が帰ってくるか、
確認してみます。

1. Vue.js側のAxios通信の作成

試しにボタンからAPIサーバーへリクエストを送る処理を書いていきます。
戻り値を表示する部分も用意します。

ターミナル
$ docker-compose run front npm install -S axios

インストールしたAxiosをmain.jsにセッティングします。

main.js
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'

Vue.config.productionTip = false
Vue.prototype.$axios = axios
new Vue({
  render: h => h(App),
}).$mount('#app')

初期作成されたHelloWorld.vueに追記していきます。

HelloWorld.vue
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <!-- 下記記載 -->
    <h2>ここに結果が表示されます → {{ result }}</h2>
    <button @click="getAPI()">クリック!</button>
    <p>
      For a guide and recipes on how to configure / customize this project,<br>
      check out the
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
    </p>

<!-- ~~~ 割愛 ~~~ -->
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  // 下記記載
  data () {
    return {
      result: 'No Result',
      url: 'http://localhost:8000/back/testapi/get/'
    }
  },
  methods: {
    getAPI () {
      this.$axios.get(this.url)
      .then(response => {
        this.result = response.data.message
      })
    }
  }
}
</script>

2. Django側のレスポンス処理の作成

URLConfへの記載、Views.pyにてレスポンス処理を書いていきます。
今回はhello worldを返すようにします。

root側のurls.py
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('back/testapi', include('testapi.urls', namespace='testapi')),
]
App側のurls.py
from django.urls import include, path
from .views import *

app_name = 'testapi'

urlpatterns = [
    path('get/', GetTestAPI.as_view()),
]
views.py
from django.shortcuts import render
from rest_framework import status, viewsets, filters
from rest_framework import permissions
from rest_framework.response import Response

class GetTestAPI(APIView):
    permission_classes = (permissions.AllowAny,)

    def get(self, request, format=None):
        return Response(data={'status': 'Hello World!'}, status=status.HTTP_200_OK)
settings.py
# ~~ 省略 ~~

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'testapi'
]

# ~~ 省略 ~~

3. 疎通

サーバーを立ち上げてブラウザ上から確認してみます。

$ docker-compose up -d

まとめ

現在SPA+APIサーバー環境をDocker上で構築することで、
短い時間で、簡単に構築することができます。

現在弊社では、HRモンスターと呼ばれる
採用の新しいスタイルを提供するサービスをローンチいたしました。

ローンチ後のさらなる機能追加、改善などのPDCAサイクルを回すべく、
エンジニアを募集しております。
https://www.wantedly.com/projects/341182

Kubernetes、Vue.js(Javascript)、Django(Python)といったモダンな技術を使って、
開発しておりますので、もしご興味がある方はぜひ、ご応募お待ちしております。

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