20200204のdockerに関する記事は18件です。

社内環境で Docker for Windows を使うときにハマったこと

普段 Docker (for Linux) を利用している人が Docker for Windows を試したらドツボにハマったのでメモ。

server gave HTTP response to HTTPS client => insecure registry を追加する

社内環境に立てた Docker Registry が HTTPS に対応していない場合、イメージを pull したときに以下のようなエラーが発生します:

ERROR: Get http://<社内レジストリ>:5000  http: server gave HTTP response to HTTPS client

このような場合、当該レジストリを insecure registry として登録すれば解決します。Linux の場合は /etc/docker/daemon.json を編集しますが、Docker for Windows の場合は [Settings] - [Docker Engine] で編集します:

daemon.json
{
  "insecure-registries" : ["<社内レジストリ>:5000"]
}

このとき注意すべきことは、プロコトルは記述しないということです。記述しても問題なく適用&再起動できてしまうので注意してください。間違った設定のせいで Settings が開けなくなった場合はあきらめて再インストールしてください。

dial tcp: lookup registry-1.docker.io: no such host. => プロキシを設定する

環境にある Docker Registory (公式など) から pull したときに以下のようなエラーが発生する場合があります:

docker: Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: no such host.

そんなホストみつからないよ!といっていますが DNS の問題ではなく、プロキシが効いていないためのエラーです。そのため、[Settings] - [Resources] - [Proxies] でプロキシの設定を行います。プロキシサーバに BASIC 認証がかかっている場合は以下のように設定します。

http://<ユーザ名>:<パスワード>@<プロキシサーバ>:<ポート>

これでも同様なエラーが発生する場合は、[Settings] - [Resources] - [Network] で DNS として 8.8.8.8 を指定するとパスできるという情報もありますが詳細は混沌の中です。

参考リンク

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

Docker for WindowsでLaravel+OCI8の複数プロジェクト開発環境を作ってみた

普段レガシーなシステムをごにょごにょお世話しているレガシーなプログラマーです。
中高年でもイマドキ風の開発をやってみたい!
でも仕事で使うDBはうちはORACLEが多い…
ということで、LaravelでOCIを使える環境を作ってみました。

普通に開発環境を作るならLaraDockが色々揃っていますし、他に良い記事が沢山あると思います
Laravelの開発環境をDockerを使って構築する

Docker Desktop on Windowsのインストール

まずはDockerの準備です。動作条件を確認。

  • Windows10 pro 64bit
  • メモリは4GB以上
  • Hyper-Vが使えること

ほぼこちらの説明通りで設定できました。ありがとうございます!
https://qiita.com/ksh-fthr/items/6b1242c010fac7395a45

ダウンロード&インストール

公式サイトからインストーラーをダウンロードします。
この時、Docker Hubのアカウントも作成することになります。サクッと登録しましょう。

https://docs.docker.com/docker-for-windows/install/
image.png

docker-composeのインストール

Docker for Macは個別に入れなくてもよかったのですがWindows版は手動で入れないといけません。
1.Powershell を管理者権限で起動する。
2.以下のコマンドを実行する。DockerのUpdateのたびに実行する必要があるのがメンドイ。

Invoke-WebRequest "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-Windows-x86_64.exe" -UseBasicParsing -OutFile $Env:ProgramFiles\docker\docker-compose.exe

Shared Drivesの設定

チェックを入れて「Apply」をクリック。
Dockerを再起動してちゃんと設定できているか確認します。
image.png

docker-compose.yml作成

こんな構成で作成しました。
[lara73oci]
├ docker-compose.yml
├ [nginx]
│ ├ [sites] <=ここにサイトの設定を入れる
│ ├ Dockerfile
│ └ nginx.conf
├ [php7.3]
│ ├ Dockerfile
│ ├ instantclient-basic-linux.x64-12.2.0.1.0.zip <=Oracleからダウンロードしてきます
│ ├ instantclient-sdk-linux.x64-12.2.0.1.0.zip <=Oracleからダウンロードしてきます
│ ├ php.ini
│ └ tnsnames.ora
├ [src]  <=ここにプログラム
└ [logs] <=nginxのログ

docker-compose.yml
version: '3'
services:
  nginx:
    build:
      context: ./nginx
    volumes:
      - ./src:/var/www:cached
      - ./logs/nginx/:/var/log/nginx
      - ./nginx/sites/:/etc/nginx/sites-available
    ports:
      - "80:80"
    depends_on:
      - php-fpm
  php-fpm:
    build:
      context: ./php7.3
      dockerfile: Dockerfile
    volumes:
      - ./php7.3/php.ini:/usr/local/etc/php/php.ini
      - ./php7.3/tnsnames.ora:/usr/local/instantclient/tnsnames.ora
      - ./src:/var/www:cached
    expose:
      - "9000"

複数プロジェクトを動かしたかったのでsites-availableを使っています。

nginx

nginx/Dockerfile
FROM nginx:alpine

COPY nginx.conf /etc/nginx/

RUN apk update \
    && apk upgrade \
    && apk add --no-cache bash

RUN set -x ; \
    addgroup -g 82 -S www-data ; \
    adduser -u 82 -D -S -G www-data www-data && exit 0 ; exit 1

RUN rm /etc/nginx/conf.d/default.conf

CMD ["nginx"]

EXPOSE 80 443
nginx/nginx.conf
user www-data;
worker_processes 4;
pid /run/nginx.pid;
daemon off;

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

http {
  server_tokens off;
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 15;
  types_hash_max_size 2048;
  client_max_body_size 20M;
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  access_log /dev/stdout;
  error_log /dev/stderr;
  gzip on;
  gzip_disable "msie6";

  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-available/*.conf;
  open_file_cache off; # Disabled for issue 619
  charset UTF-8;
}

サイトの設定です。

nginx/sites/default.conf
server {

  listen 80 default_server;
  listen [::]:80 default_server ipv6only=on;

  server_name localhost;
  root /var/www/public;
  index index.php index.html index.htm;

  location / {
     try_files $uri $uri/ /index.php$is_args$args;
  }

  location ~ \.php$ {
    try_files $uri /index.php =404;
    fastcgi_pass php-fpm:9000;
    fastcgi_index index.php;
    fastcgi_buffers 16 16k;
    fastcgi_buffer_size 32k;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    #fixes timeouts
    fastcgi_read_timeout 600;
    include fastcgi_params;
  }

  location ~ /\.ht {
    deny all;
  }

  location /.well-known/acme-challenge/ {
    root /var/www/letsencrypt/;
    log_not_found off;
  }
}

複数プロジェクトで使用する場合

nginx/sitesのproject1.confをコピーして使用してください

(例)project_hoge.conf

ファイル内のproject1、project1.local を自分のプロジェクトに合わせて変更してください
もちろんDocument rootも!

PHP+OCI8

Oracle instant clientの入手

Instant Client for Linux x86-64からinstantclient-basicとinstantclient-sdkをzip形式でダウンロードして
php7.3のDockerFileと同じディレクトリに置いてください
バージョンは12.2と12.1で確認しました
(例)
./php7.3/instantclient-sdk-linux.x64-12.2.0.1.0.zip
./php7.3/instantclient-basic-linux.x64-12.2.0.1.0.zip

php7.3/DockerFileの編集

入手したファイル名に合わせて13~25行目を変更してください

php7.3/tnsnames.oraの編集

ご自分の環境に合わせて記述してください

php7.3/Dockerfile
FROM php:7.3-fpm

RUN apt-get update && \
  apt-get install -y git \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev && \
  docker-php-ext-install gd pdo_mysql mysqli mbstring bcmath

ENV LD_LIBRARY_PATH /usr/local/instantclient/
ENV TNS_ADMIN /usr/local/instantclient/

COPY instantclient-basic-linux.x64-12.2.0.1.0.zip /tmp
COPY instantclient-sdk-linux.x64-12.2.0.1.0.zip /tmp

RUN apt-get update && \
    apt-get install -y zip unzip libaio1 wget && \
    unzip /tmp/instantclient-basic-linux.x64-12.2.0.1.0.zip -d /usr/local/ && \
    unzip /tmp/instantclient-sdk-linux.x64-12.2.0.1.0.zip -d /usr/local/ && \
    ln -s /usr/local/instantclient_12_2 /usr/local/instantclient && \
    ln -s /usr/local/instantclient/libclntsh.so.12.1 /usr/local/instantclient/libclntsh.so && \
    export LD_LIBRARY_PATH=/usr/local/instantclient && \
    docker-php-ext-configure oci8 --with-oci8=instantclient,/usr/local/instantclient && \
    docker-php-ext-install oci8 && \ 
    docker-php-ext-configure pdo_oci --with-pdo-oci=instantclient,/usr/local/instantclient,12.2 && \
    docker-php-ext-install pdo_oci && \
    rm -rf /usr/local/*.zip

RUN apt-get install -y \
    curl \
    gnupg
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN apt-get install -y nodejs
RUN npm install npm@latest -g

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

Laravel用にnpmやcomposerも入るようにしています
Oracle instant client導入~OCI8のインストール部分は
LaraDockのworkspaceとphp-fpmのDockerfileに同様の設定をいれると動くと思います。
LaraDockでやりたい方はお試しあれ!

/etc/hostsを変更

Windows10の場合はC:\Windows\System32\drivers\etc\hosts
管理者モードでメモ帳を起動して設定したホスト名を追記します。
これで http://project1.local/ でアクセスできるようになります。

127.0.0.1   project1.local
::1 project1.local
127.0.0.1   project2.local
::1 project2.local

起動

docker-compose up -d

LaravelのインストールとOCI8設定

1.php-fpmに入ります

docker-compose exec php-fpm bash

2.Laravelのインストール

$ cd /var/www  <=設定したドキュメントルートに合うようにしてください
$ composer create-project --prefer-dist laravel/laravel project1 "5.8.*" <=5.8の場合
$ composer create-project --prefer-dist laravel/laravel project1 <=最新版

3.yajra/laravel-oci8のインストール
https://github.com/yajra/laravel-oci8
ドキュメント通りにLaravelのバージョンにあわせてcomposerでインストールします
Laravelのディレクトリに移動して

$ composer require yajra/laravel-oci8:"5.8.*"  <=Laravel5.8
$ composer require yajra/laravel-oci8:"^6.0"     <=Laravel6~

4.Laravelのconfig/app.phpのproviders内に追加します

config/app.php
'providers' => [
    // ...
    Yajra\Oci8\Oci8ServiceProvider::class,
],

5.config/oracle.phpの作成

php artisan vendor:publish --tag=oracle

6..env内のORACLEの設定

.env
DB_CONNECTION=oracle
DB_HOST=xxx.xxx.xxx.xxx
DB_PORT=1521
DB_DATABASE=oracleのSID
DB_USERNAME=xxx
DB_PASSWORD=xxx

以上でMySQLと同じようにDBの操作ができました。

リポジトリ

作成したOracle instant client本体なしの雛形リポジトリを置いておきます。
Docker初心者なのでここはこうしたほうがいいよと教えていただけると嬉しいです!
https://github.com/anissia0828/nginx_php73_oci

参考にさせていただきました

laravelでoracleと接続する方法
【Laravel】Laradockで複数プロジェクトを動かす手順

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

MobileNetV2-SSDLiteのPascal-VOCデータセットによる学習 [Docker版リメイク]

PINTO_model_zoo GitHub stars

1. Introduction

1年前に記事にしたMobileNetV2-SSDLiteのトレーニング環境構築記事を超簡易仕様にリメイクしました。 GPU対応版の最新のDockerが導入されている段階から作業に着手すると、15分ほどでトレーニングを開始できると思います。 ミスり要素はほぼ無いと思います。 学習が終わったらトレーニング済みモデル(.ckpt/.pb)の Integer Quantization を実施して Github へコミットする予定です。 トレーニング用データセットの前処理など、全ての処理はシェルスクリプト内に記載してありますので、気になる方は constants.sh あるいは prepare_checkpoint_and_dataset.sh あるいは retrain_detection_model.sh の内容をご覧ください。

2. Environment

  • Ubuntu 18.04 x86_64, RAM 16GB, Geforce GTX1070
  • Tensorflow-GPU v1.15.2
  • Docker 19.03.5
  • Pascal VOC 2012/2007 Dataset
  • MobileNetV2-SSDLite

3. Procedure

Creating_Docker_files
$ DETECT_DIR=${HOME}/edgetpu/detection && mkdir -p $DETECT_DIR
$ cd $DETECT_DIR && nano Dockerfile
Dockerfile
### Ubuntu 18.04

FROM tensorflow/tensorflow:1.15.2-gpu-py3

RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y \
    protobuf-compiler python-pil python-lxml python-tk \
    autoconf automake libtool curl make g++ unzip wget git nano \
    libgflags-dev libgoogle-glog-dev liblmdb-dev libleveldb-dev \
    libhdf5-serial-dev libhdf5-dev python3-opencv python-opencv \
    python3-dev python3-numpy python3-skimage gfortran libturbojpeg \
    python-dev python-numpy python-skimage python3-pip python-pip \
    libboost-all-dev libopenblas-dev libsnappy-dev software-properties-common \
    protobuf-compiler python-pil python-lxml python-tk libfreetype6-dev pkg-config \
    libpng-dev libhdf5-100 libhdf5-cpp-100

# Get the tensorflow models research directory, and move it into tensorflow source folder to match recommendation of installation
RUN git clone https://github.com/tensorflow/models.git && \
    mkdir -p /tensorflow && \
    mv models /tensorflow


# Install the Tensorflow Object Detection API from here
# https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/installation.md

# Install object detection api dependencies
RUN pip3 install Cython && \
    pip3 install contextlib2 && \
    pip3 install pillow && \
    pip3 install lxml && \
    pip3 install jupyter && \
    pip3 install matplotlib && \
    pip2 install Cython && \
    pip2 install contextlib2 && \
    pip2 install pillow && \
    pip2 install lxml && \
    pip2 install jupyter && \
    pip2 install matplotlib

# Get protoc 3.0.0, rather than the old version already in the container
RUN curl -OL "https://github.com/google/protobuf/releases/download/v3.0.0/protoc-3.0.0-linux-x86_64.zip" && \
    unzip protoc-3.0.0-linux-x86_64.zip -d proto3 && \
    mv proto3/bin/* /usr/local/bin && \
    mv proto3/include/* /usr/local/include && \
    rm -rf proto3 protoc-3.0.0-linux-x86_64.zip

# Install pycocoapi
RUN git clone --depth 1 https://github.com/cocodataset/cocoapi.git && \
    cd cocoapi/PythonAPI && \
    make -j8 && \
    cp -r pycocotools /tensorflow/models/research && \
    cd ../../ && \
    rm -rf cocoapi

# Run protoc on the object detection repo
RUN cd /tensorflow/models/research && \
    protoc object_detection/protos/*.proto --python_out=.

# Set the PYTHONPATH to finish installing the API
ENV PYTHONPATH $PYTHONPATH:/tensorflow/models/research:/tensorflow/models/research/slim

# Install wget (to make life easier below) and editors (to allow people to edit the files inside the container)
RUN apt-get update && \
    apt-get install -y wget nano

ARG work_dir=/tensorflow/models/research
# Get object detection transfer learning scripts.
ARG scripts_link="http://storage.googleapis.com/cloud-iot-edge-pretrained-models/docker/obj_det_scripts.tgz"
RUN cd ${work_dir} && \
    wget -O obj_det_scripts.tgz ${scripts_link} && \
    tar zxvf obj_det_scripts.tgz

WORKDIR ${work_dir}

Ctrl + O
Ctrl + X

Build_a_Docker_image
$ docker build - < Dockerfile --tag training_container
Start_Docker_container
$ docker run \
  --runtime=nvidia \
  --name training_container \
  -it \
  --privileged \
  -p 6006:6006 \
  training_container \
  /bin/bash

Screenshot 2020-02-04 11:37:06.png

Download_training_shell_script
### Download constants.sh
$ curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=1e74pfaoHqp6WiWwTGamzN7wNRTDoR3q3" > /dev/null
$ CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
$ curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=1e74pfaoHqp6WiWwTGamzN7wNRTDoR3q3" -o constants.sh

### Download prepare_checkpoint_and_dataset.sh
$ curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=1Rk2VRGBwZnlcfl3DmryPMbNpICJ2R-vr" > /dev/null
$ CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
$ curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=1Rk2VRGBwZnlcfl3DmryPMbNpICJ2R-vr" -o prepare_checkpoint_and_dataset.sh

### Download retrain_detection_model.sh
$ curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=1MbjoqxBG56aDyvGxBbJd1QCbGo4nDKnm" > /dev/null
$ CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
$ curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=1MbjoqxBG56aDyvGxBbJd1QCbGo4nDKnm" -o retrain_detection_model.sh

constants.sh
constants.sh
#!/bin/bash

declare -A ckpt_link_map
declare -A ckpt_name_map
declare -A config_filename_map

ckpt_link_map["mobilenet_v2_ssdlite"]="http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz"
ckpt_name_map["mobilenet_v2_ssdlite"]="ssdlite_mobilenet_v2_coco_2018_05_09"
config_filename_map["mobilenet_v2_ssdlite-true"]="pipeline_mobilenet_v2_ssdlite_retrain_whole_model.config"

INPUT_TENSORS='normalized_input_image_tensor'
OUTPUT_TENSORS='TFLite_Detection_PostProcess,TFLite_Detection_PostProcess:1,TFLite_Detection_PostProcess:2,TFLite_Detection_PostProcess:3'

OBJ_DET_DIR="$PWD"

#rm -rf "${OBJ_DET_DIR}/learn"
mkdir -p "${OBJ_DET_DIR}/learn"
LEARN_DIR="${OBJ_DET_DIR}/learn"

#rm -rf "${LEARN_DIR}/data"
#rm -rf "${LEARN_DIR}/ckpt"
#rm -rf "${LEARN_DIR}/train"
#rm -rf "${LEARN_DIR}/models"
mkdir -p "${LEARN_DIR}/data"
mkdir -p "${LEARN_DIR}/ckpt"
mkdir -p "${LEARN_DIR}/train"
mkdir -p "${LEARN_DIR}/models"
DATASET_DIR="${LEARN_DIR}/data"
CKPT_DIR="${LEARN_DIR}/ckpt"
TRAIN_DIR="${LEARN_DIR}/train"
OUTPUT_DIR="${LEARN_DIR}/models"


prepare_checkpoint_and_dataset.sh
prepare_checkpoint_and_dataset.sh
#!/bin/bash

# Exit script on error.
set -e
# Echo each command, easier for debugging.
set -x

usage() {
  cat << END_OF_USAGE
  Downloads checkpoint and dataset needed for the tutorial.

  --network_type      Can be one of [mobilenet_v1_ssd, mobilenet_v2_ssd],
                      mobilenet_v1_ssd by default.
  --train_whole_model Whether or not to train all layers of the model. false
                      by default, in which only the last few layers are trained.
  --help              Display this help.
END_OF_USAGE
}

network_type="mobilenet_v2_ssdlite"
train_whole_model="true"
while [[ $# -gt 0 ]]; do
  case "$1" in
    --network_type)
      network_type=$2
      shift 2 ;;
    --train_whole_model)
      train_whole_model=$2
      shift 2;;
    --help)
      usage
      exit 0 ;;
    --*)
      echo "Unknown flag $1"
      usage
      exit 1 ;;
  esac
done

source "$PWD/constants.sh"

echo "PREPARING checkpoint..."
mkdir -p "${LEARN_DIR}"

ckpt_link="${ckpt_link_map[${network_type}]}"
ckpt_name="${ckpt_name_map[${network_type}]}"
cd "${LEARN_DIR}"
rm -rf "${CKPT_DIR}/${ckpt_name}"
wget -O "${CKPT_DIR}/${ckpt_name}.tar.gz" "$ckpt_link"
tar -zxvf "${CKPT_DIR}/${ckpt_name}.tar.gz" -C "${CKPT_DIR}"
rm "${CKPT_DIR}/${ckpt_name}.tar.gz"
rm -rf "${CKPT_DIR}/saved_model"
cp -r ${CKPT_DIR}/${ckpt_name}/* "${CKPT_DIR}/"

echo "CHOSING config file..."
cd "${OBJ_DET_DIR}"
curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=1IoHkfxfkXSUM8nnevrb_dVct72fMJ7t2" > /dev/null
CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=1IoHkfxfkXSUM8nnevrb_dVct72fMJ7t2" -o pipeline.config
mv pipeline.config "${CKPT_DIR}"

echo "REPLACING variables in config file..."
sed -i "s%PATH_TO_BE_CONFIGURED/model.ckpt%${CKPT_DIR}/model.ckpt%g" "${CKPT_DIR}/pipeline.config"
sed -i "s%PATH_TO_BE_CONFIGURED/mscoco_label_map.pbtxt%${DATASET_DIR}/pascal_label_map.pbtxt%g" "${CKPT_DIR}/pipeline.config"
sed -i "s%PATH_TO_BE_CONFIGURED/mscoco_train.record%${DATASET_DIR}/pascal_train.record%g" "${CKPT_DIR}/pipeline.config"
sed -i "s%PATH_TO_BE_CONFIGURED/mscoco_val.record%${DATASET_DIR}/pascal_val.record%g" "${CKPT_DIR}/pipeline.config"

echo "PREPARING dataset"
rm -rf "${DATASET_DIR}"
mkdir -p "${DATASET_DIR}"
cd "${DATASET_DIR}"

# VOCtrainval_11-May-2012.tar <--- 1.86GB
curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=1rATNHizJdVHnaJtt-hW9MOgjxoaajzdh" > /dev/null
CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=1rATNHizJdVHnaJtt-hW9MOgjxoaajzdh" -o VOCtrainval_11-May-2012.tar

# VOCtrainval_06-Nov-2007.tar <--- 460MB
curl -sc /tmp/cookie "https://drive.google.com/uc?export=download&id=1c8laJUn-aaWEhE5NlDwIdNv5ZdogUAcD" > /dev/null
CODE="$(awk '/_warning_/ {print $NF}' /tmp/cookie)"
curl -Lb /tmp/cookie "https://drive.google.com/uc?export=download&confirm=${CODE}&id=1c8laJUn-aaWEhE5NlDwIdNv5ZdogUAcD" -o VOCtrainval_06-Nov-2007.tar

# Extract the data.
tar -xvf VOCtrainval_11-May-2012.tar && rm VOCtrainval_11-May-2012.tar
tar -xvf VOCtrainval_06-Nov-2007.tar && rm VOCtrainval_06-Nov-2007.tar

echo "PREPARING label map..."
cd "${OBJ_DET_DIR}"
cp "object_detection/data/pascal_label_map.pbtxt" "${DATASET_DIR}"

echo "CONVERTING dataset to TF Record..."
protoc object_detection/protos/*.proto --python_out=.

python3 object_detection/dataset_tools/create_pascal_tf_record.py \
  --label_map_path="${DATASET_DIR}/pascal_label_map.pbtxt" \
  --data_dir=${DATASET_DIR}/VOCdevkit \
  --year=merged \
  --set=train \
  --output_path="${DATASET_DIR}/pascal_train.record"

python3 object_detection/dataset_tools/create_pascal_tf_record.py \
  --label_map_path="${DATASET_DIR}/pascal_label_map.pbtxt" \
  --data_dir=${DATASET_DIR}/VOCdevkit \
  --year=merged \
  --set=val \
  --output_path="${DATASET_DIR}/pascal_val.record"


retrain_detection_model.sh
retrain_detection_model.sh
#!/bin/bash

# Exit script on error.
set -e
# Echo each command, easier for debugging.
set -x

usage() {
  cat << END_OF_USAGE
  Starts retraining detection model.

  --num_training_steps Number of training steps to run, 500 by default.
  --num_eval_steps     Number of evaluation steps to run, 100 by default.
  --help               Display this help.
END_OF_USAGE
}

num_training_steps=200000
while [[ $# -gt 0 ]]; do
  case "$1" in
    --num_training_steps)
      num_training_steps=$2
      shift 2 ;;
    --num_eval_steps)
      num_eval_steps=$2
      shift 2 ;;    
    --help)
      usage
      exit 0 ;;
    --*)
      echo "Unknown flag $1"
      usage
      exit 1 ;;
  esac
done

source "$PWD/constants.sh"

python3 object_detection/model_main.py \
  --pipeline_config_path="${CKPT_DIR}/pipeline.config" \
  --model_dir="${TRAIN_DIR}" \
  --num_train_steps="${num_training_steps}" \
  --num_eval_steps="${num_eval_steps}"

Granting_execution_authority_to_script_files
$ chmod +x constants.sh
$ chmod +x prepare_checkpoint_and_dataset.sh
$ chmod +x retrain_detection_model.sh
Data_preparation_and_Training
### Data preparation
$ ./prepare_checkpoint_and_dataset.sh

### Training
$ NUM_TRAINING_STEPS=1000000 && \
  NUM_EVAL_STEPS=100 && \
  rm -rf learn/train && \
  ./retrain_detection_model.sh \
    --num_training_steps ${NUM_TRAINING_STEPS} \
    --num_eval_steps ${NUM_EVAL_STEPS}
check_the_progress_of_learning
### Check learning status with Tensorboard
$ docker exec -it training_container /bin/bash
$ cd learn/train
$ tensorboard --logdir=.

<Progress of learning>
FireShot Capture 009 - TensorBoard - localhost.png
FireShot Capture 010 - TensorBoard - localhost.png

Extract_files_from_Docker_container
$ docker cp 07a048c6b1b8:/tensorflow/models/research/learn/train/model.ckpt-7044.data-00000-of-00001 .
$ docker cp 07a048c6b1b8:/tensorflow/models/research/learn/train/model.ckpt-7044.index .
$ docker cp 07a048c6b1b8:/tensorflow/models/research/learn/train/model.ckpt-7044.meta .
$ docker cp 07a048c6b1b8:/tensorflow/models/research/learn/train/graph.pbtxt .
$ docker cp 07a048c6b1b8:/tensorflow/models/research/learn/train/checkpoint .
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker for windows環境にてPowershellでCtrl+zが使用できない問題の解決法(仮)

Docker for windows環境にてPowershellを使ってDocker上のLinuxをCUI操作している場合、Ctrl+zでLinuxにシグナルを送ろうとしても上手く動作しない。
Ctrl+zがPowershellの操作に割り当てられている様子。Linuxを抜けてPowershellの操作に戻ってしまう。
簡単な解決法として、Powershellで「レガシーコンソール」を使用することで解決した。

プロパティから「レガシーコンソール」を選択するだけ

PowerShellのバー上で右クリック → プロパティを選択
クリップボード一時ファイル01.png

「レガシーコンソールを使用する」にチェックを入れる
クリップボード一時ファイル02.png

これ以外のもっとエレガントな解決方法がきっとあるはずである。

参考:Windows PowerShell, Control-Z, and Kitematic
https://alankent.me/2017/07/04/windows-powershell-control-z-and-kitemati/

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

図解: Cluster APIを使ってKubernetesクラスタを作る (on Docker)

Cluster APIを使うと何ができるのか

Cluster APIとは、クラスタ管理を宣言的APIで実現するKubernetesプロジェクトです。
Quickstartを実行することで、Cluster APIの実現機能が把握できます。

今回は、このQuickstartの流れを実機で試してみます。流れをまとめた次のような4コマ漫画を作りました。

1. 最初はManagement Clusterだけがあります。
first.png
2. Clusterを追加すると、クラスタが新規作成されますが、
中には何もありません
cluster.png
3. Machineを追加すると、マスターノードが追加されます。
machine.png
4. MachineDeploymentを追加すると、ワーカノード追加が追加されます。
last.png

以下ではこの流れに沿って、手順を実行してみます。

環境

今回は、Docker Desktop for mac v2.2.0.0 がインストールされたMacbook Proで実施しました。その他以下がインストールされています。

  • kind 1.17

Management Clusterの準備

まずは4コマ漫画の1コマ目です。Cluster APIを持つクラスタ、Management Clusterを用意します。

first.png

最小限のKubernetesの準備

Cluster APIをインストールするには、Kubernetesクラスタが必要です。このクラスタをManagement Clusterといいます。クラスタを作る前にクラスタが必要というのは、少し手間なように感じます。でもAPIが利用できればよいので、マスターノードだけでかまいません。

ここでは、kindというツールを使いマスターノード1台だけの最小限のクラスタを用意します。control-planeというのは、kindの設定でマスターノードと言う意味です。

cat > kind-cluster-with-extramounts.yaml <<EOF
kind: Cluster
apiVersion: kind.sigs.k8s.io/v1alpha3
nodes:
- role: control-plane
  extraMounts:
    - hostPath: /var/run/docker.sock
      containerPath: /var/run/docker.sock
EOF
kind create cluster --config ./kind-cluster-with-extramounts.yaml --name clusterapi

Cluster API のインストール

Cluster APIは、設定ファイルに相当するCRD (CustomResourceDefinition)と、その設定にしたがってクラスタを作成するcontroller-managerからなります。これらを一括でインストールします。

kubectl create -f https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.2.9/cluster-api-components.yaml

namespace/capi-system created
customresourcedefinition.apiextensions.k8s.io/clusters.cluster.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/machinedeployments.cluster.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/machines.cluster.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/machinesets.cluster.x-k8s.io created
role.rbac.authorization.k8s.io/capi-leader-election-role created
clusterrole.rbac.authorization.k8s.io/capi-manager-role created
rolebinding.rbac.authorization.k8s.io/capi-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/capi-manager-rolebinding created
deployment.apps/capi-controller-manager created

次に、実際の環境に合わせたブートストラップとプロバイダをインストールします。
今回は、Dockerだけの環境を使いますので、ブートストラップにKubeadmを、プロバイダにDocker用のものを使います。
以下の専用コンポーネントをインストールします。

kubectl create -f https://github.com/kubernetes-sigs/cluster-api-bootstrap-provider-kubeadm/releases/download/v0.1.5/bootstrap-components.yaml

namespace/cabpk-system created
customresourcedefinition.apiextensions.k8s.io/kubeadmconfigs.bootstrap.cluster.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/kubeadmconfigtemplates.bootstrap.cluster.x-k8s.io created
role.rbac.authorization.k8s.io/cabpk-leader-election-role created
clusterrole.rbac.authorization.k8s.io/cabpk-manager-role created
clusterrole.rbac.authorization.k8s.io/cabpk-proxy-role created
rolebinding.rbac.authorization.k8s.io/cabpk-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/cabpk-manager-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/cabpk-proxy-rolebinding created
service/cabpk-controller-manager-metrics-service created
deployment.apps/cabpk-controller-manager created

kubectl get po -n cabpk-system   
NAME                                       READY   STATUS    RESTARTS   AGE
cabpk-controller-manager-c58d8596f-rqczh   2/2     Running   0          7m13s
kubectl create -f https://github.com/kubernetes-sigs/cluster-api-provider-docker/releases/download/v0.2.1/provider-components.yaml

namespace/capd-system created
customresourcedefinition.apiextensions.k8s.io/dockerclusters.infrastructure.cluster.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/dockermachines.infrastructure.cluster.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/dockermachinetemplates.infrastructure.cluster.x-k8s.io created
role.rbac.authorization.k8s.io/capd-leader-election-role created
clusterrole.rbac.authorization.k8s.io/capd-manager-role created
clusterrole.rbac.authorization.k8s.io/capd-proxy-role created
rolebinding.rbac.authorization.k8s.io/capd-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/capd-manager-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/capd-proxy-rolebinding created
service/capd-controller-manager-metrics-service created
deployment.apps/capd-controller-manager created

kubectl get po -n capd-system 
NAME                                      READY   STATUS    RESTARTS   AGE
capd-controller-manager-7cd8c765c-84j7r   2/2     Running   0          5m22s

この時点で、Docker上にはclusterapi-control-planeというコンテナ(Management cluster)が一つだけ動いています。

docker ps    
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                       NAMES
68d711500e26        kindest/node:v1.17.0   "/usr/local/bin/entr…"   11 minutes ago      Up 11 minutes       127.0.0.1:32775->6443/tcp   clusterapi-control-plane

ClusterAPIを使う

Cluster APIの以下のCRDを順に作成していきます。

  • Cluster
  • Machine
  • MachineDeployment

Cluster新規作成

4コマ漫画の2コマ目になります。

cluster.png

Cluster APIで作るためのクラスタの設定ファイルを作成します。

cluster.yaml
apiVersion: cluster.x-k8s.io/v1alpha2
kind: Cluster
metadata:
  name: capi-quickstart
spec:
  clusterNetwork:
    pods:
      cidrBlocks: ["192.168.0.0/16"]
  infrastructureRef:
    apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
    kind: DockerCluster
    name: capi-quickstart
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
kind: DockerCluster
metadata:
  name: capi-quickstart
kubectl create -f cluster.yaml
cluster.cluster.x-k8s.io/capi-quickstart created
dockercluster.infrastructure.cluster.x-k8s.io/capi-quickstart created
kubectl get dockercluster 
NAME              AGE
capi-quickstart   11s

Dockerを確認してみますと、以下のようにcapi-quickstart-lbというコンテナが起動していることがわかります。

 docker ps 
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                                        NAMES
38d5a9338e3d        nginx:1.15.12-alpine   "nginx -g 'daemon of…"   48 seconds ago      Up 47 seconds       80/tcp, 40319/tcp, 0.0.0.0:40319->6443/tcp   capi-quickstart-lb
68d711500e26        kindest/node:v1.17.0   "/usr/local/bin/entr…"   14 minutes ago      Up 14 minutes       127.0.0.1:32775->6443/tcp                    clusterapi-control-plane

Machineを作る

4コマ漫画の3コマ目になります。MachineというCRDでマスターノードを作成します。

machine.png

machine.yaml
apiVersion: cluster.x-k8s.io/v1alpha2
kind: Machine
metadata:
  name: capi-quickstart-controlplane-0
  labels:
    cluster.x-k8s.io/control-plane: "true"
    cluster.x-k8s.io/cluster-name: "capi-quickstart"
spec:
  version: v1.15.3
  bootstrap:
    configRef:
      apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
      kind: KubeadmConfig
      name: capi-quickstart-controlplane-0
  infrastructureRef:
    kind: DockerMachine
    apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
    name: capi-quickstart-controlplane-0
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
kind: DockerMachine
metadata:
  name: capi-quickstart-controlplane-0
---
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
kind: KubeadmConfig
metadata:
  name: capi-quickstart-controlplane-0
spec:
  initConfiguration:
    nodeRegistration:
      kubeletExtraArgs:
        eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
  clusterConfiguration:
    controllerManager:
      extraArgs:
        enable-hostpath-provisioner: "true"
kubectl create -f machine.yaml
machine.cluster.x-k8s.io/capi-quickstart-controlplane-0 created
dockermachine.infrastructure.cluster.x-k8s.io/capi-quickstart-controlplane-0 created
kubeadmconfig.bootstrap.cluster.x-k8s.io/capi-quickstart-controlplane-0 created

以下のようにmachineが起動されるまでにおおよそ10分かかりました。

kubectl get machines --selector cluster.x-k8s.io/control-plane

NAME                             PROVIDERID                                                  PHASE
capi-quickstart-controlplane-0   docker:////capi-quickstart-capi-quickstart-controlplane-0   running

Dockerでも以下のように、capi-quickstart-capi-quickstart-controlplane-0というコンテナが起動したことがわかります。

docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED              STATUS              PORTS                                        NAMES
f449784405e6        kindest/node:v1.15.3   "/usr/local/bin/entr…"   About a minute ago   Up About a minute   35547/tcp, 127.0.0.1:35547->6443/tcp         capi-quickstart-capi-quickstart-controlplane-0
38d5a9338e3d        nginx:1.15.12-alpine   "nginx -g 'daemon of…"   11 minutes ago       Up 11 minutes       80/tcp, 40319/tcp, 0.0.0.0:40319->6443/tcp   capi-quickstart-lb
68d711500e26        kindest/node:v1.17.0   "/usr/local/bin/entr…"   25 minutes ago       Up 25 minutes       127.0.0.1:32775->6443/tcp                    clusterapi-control-plane

作成したクラスタにアクセスするkubeconfigを作る

kubectlでクラスタ内に接続するために、kubeconfigファイルを作成します。予めcluster作成時に以下のようなSecretが作成されているので、そこから抜き出します。

kubectl --namespace=default get secret/capi-quickstart-kubeconfig -o json \
  | jq -r .data.value \
  | base64 --decode \
  > ./capi-quickstart.kubeconfig

今回はMacbook上で実行したために、以下のコマンドで一部だけ変更します(clusterの宛先と接続方法insecure-skip-tls-verifyを変更します。)

sed -i -e "s/server:.*/server: https:\/\/$(docker port capi-quickstart-lb 6443/tcp | sed "s/0.0.0.0/127.0.0.1/")/g" ./capi-quickstart.kubeconfig

# Ignore the CA, because it is not signed for 127.0.0.1
sed -i -e "s/certificate-authority-data:.*/insecure-skip-tls-verify: true/g" ./capi-quickstart.kubeconfig

生成したkubeconfigはこうなっています。

capi-quickstart.kubeconfig
apiVersion: v1
clusters:
- cluster:
    insecure-skip-tls-verify: true
    server: https://127.0.0.1:40319
  name: capi-quickstart
contexts:
- context:
    cluster: capi-quickstart
    user: kubernetes-admin
  name: kubernetes-admin@capi-quickstart
current-context: kubernetes-admin@capi-quickstart
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: LS0tLS1CR...
    client-key-data: LS0t...

このkubeconfigを使ってkubectlを実行してみます。

kubectl --kubeconfig=./capi-quickstart.kubeconfig get nodes 
NAME                                             STATUS     ROLES    AGE     VERSION
capi-quickstart-capi-quickstart-controlplane-0   NotReady   master   8m35s   v1.15.3

まずはMasterノードが動いていることがわかります。ただし、状態はまだNotReadyです。クラスタ内ネットワークが構築されていないためです。

クラスタ内ネットワークを構築する

次に、ネットワークを構築します。calicoをインストールします。

calico.png

kubectl --kubeconfig=./capi-quickstart.kubeconfig \
  apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml

configmap/calico-config created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created
clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrole.rbac.authorization.k8s.io/calico-node created
clusterrolebinding.rbac.authorization.k8s.io/calico-node created
daemonset.apps/calico-node created
serviceaccount/calico-node created
deployment.apps/calico-kube-controllers created
serviceaccount/calico-kube-controllers created
kubectl --kubeconfig=./capi-quickstart.kubeconfig \
  -n kube-system patch daemonset calico-node \
  --type=strategic --patch='
spec:
  template:
    spec:
      containers:
      - name: calico-node
        env:
        - name: FELIX_IGNORELOOSERPF
          value: "true"
'
daemonset.extensions/calico-node patched

これを実行することにより、マスターノードはReady状態となります。

Workerを追加する

4コマ漫画の最後のコマになります。ワーカーノードをMachineDeploymentを使って追加します。

last.png

以下のworker.yamlファイルを作成し、Management Clusterに対しkubectl createコマンドを実行します。

worker.yaml
apiVersion: cluster.x-k8s.io/v1alpha2
kind: MachineDeployment
metadata:
  name: capi-quickstart-worker
  labels:
    cluster.x-k8s.io/cluster-name: capi-quickstart
    # Labels beyond this point are for example purposes,
    # feel free to add more or change with something more meaningful.
    # Sync these values with spec.selector.matchLabels and spec.template.metadata.labels.
    nodepool: nodepool-0
spec:
  replicas: 1
  selector:
    matchLabels:
      cluster.x-k8s.io/cluster-name: capi-quickstart
      nodepool: nodepool-0
  template:
    metadata:
      labels:
        cluster.x-k8s.io/cluster-name: capi-quickstart
        nodepool: nodepool-0
    spec:
      version: v1.15.3
      bootstrap:
        configRef:
          name: capi-quickstart-worker
          apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
          kind: KubeadmConfigTemplate
      infrastructureRef:
        name: capi-quickstart-worker
        apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
        kind: DockerMachineTemplate
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
kind: DockerMachineTemplate
metadata:
  name: capi-quickstart-worker
spec:
  template:
    spec: {}
---
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
kind: KubeadmConfigTemplate
metadata:
  name: capi-quickstart-worker
spec:
  template:
    spec:
      # For more information about these values,
      # refer to the Kubeadm Bootstrap Provider documentation.
      joinConfiguration:
        nodeRegistration:
          kubeletExtraArgs:
            eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
      clusterConfiguration:
        controllerManager:
          extraArgs:
            enable-hostpath-provisioner: "true"
kubectl create -f worker.yaml 
machinedeployment.cluster.x-k8s.io/capi-quickstart-worker created
dockermachinetemplate.infrastructure.cluster.x-k8s.io/capi-quickstart-worker created
kubeadmconfigtemplate.bootstrap.cluster.x-k8s.io/capi-quickstart-worker created
docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                                        NAMES
e6162d760dd7        kindest/node:v1.15.3   "/usr/local/bin/entr…"   2 minutes ago       Up 2 minutes                                                     capi-quickstart-capi-quickstart-worker-85cbf8fd8c-mhrlz
f449784405e6        kindest/node:v1.15.3   "/usr/local/bin/entr…"   16 minutes ago      Up 16 minutes       35547/tcp, 127.0.0.1:35547->6443/tcp         capi-quickstart-capi-quickstart-controlplane-0
38d5a9338e3d        nginx:1.15.12-alpine   "nginx -g 'daemon of…"   26 minutes ago      Up 26 minutes       80/tcp, 40319/tcp, 0.0.0.0:40319->6443/tcp   capi-quickstart-lb
68d711500e26        kindest/node:v1.17.0   "/usr/local/bin/entr…"   40 minutes ago      Up 40 minutes       127.0.0.1:32775->6443/tcp                    clusterapi-control-plane
kubectl --kubeconfig=./capi-quickstart.kubeconfig get nodes     ✔  1656  01:13:19

NAME                                                      STATUS   ROLES    AGE     VERSION
capi-quickstart-capi-quickstart-controlplane-0            Ready    master   20m     v1.15.3
capi-quickstart-capi-quickstart-worker-85cbf8fd8c-mhrlz   Ready    <none>   6m30s   v1.15.3

Workerを増やす

オプションで、MachineDeploymentを編集することで動的にワーカーノードを追加することができます。

以下では、1台だったワーカーノードを2台に増やします。

$ kubectl edit machinedeployment capi-quickstart-worker

以下の行を変更します。

- replica: 1
+ replica: 2

保存して終了します。Machineが以下のように増えています。

$ kubectl get machines
NAME                                      PROVIDERID                                                           PHASE
capi-quickstart-controlplane-0            docker:////capi-quickstart-capi-quickstart-controlplane-0            running
capi-quickstart-worker-85cbf8fd8c-mhrlz   docker:////capi-quickstart-capi-quickstart-worker-85cbf8fd8c-mhrlz   running
capi-quickstart-worker-85cbf8fd8c-wjk9h                                                                        provisioning

Dockerコンテナを見ても、以下のように追加されます。

$ docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED              STATUS              PORTS                                        NAMES
e55a1192feeb        kindest/node:v1.15.3   "/usr/local/bin/entr…"   About a minute ago   Up About a minute                                                capi-quickstart-capi-quickstart-worker-85cbf8fd8c-wjk9h
e6162d760dd7        kindest/node:v1.15.3   "/usr/local/bin/entr…"   3 days ago           Up 3 days                                                        capi-quickstart-capi-quickstart-worker-85cbf8fd8c-mhrlz
f449784405e6        kindest/node:v1.15.3   "/usr/local/bin/entr…"   3 days ago           Up 3 days           35547/tcp, 127.0.0.1:35547->6443/tcp         capi-quickstart-capi-quickstart-controlplane-0
38d5a9338e3d        nginx:1.15.12-alpine   "nginx -g 'daemon of…"   3 days ago           Up 3 days           80/tcp, 40319/tcp, 0.0.0.0:40319->6443/tcp   capi-quickstart-lb
68d711500e26        kindest/node:v1.17.0   "/usr/local/bin/entr…"   3 days ago           Up 3 days           127.0.0.1:32775->6443/tcp                    clusterapi-control-plane

kubectl get nodesコマンドでも確認できます。

$ kubectl --kubeconfig=./capi-quickstart.kubeconfig get nodes

NAME                                                      STATUS   ROLES    AGE     VERSION
capi-quickstart-capi-quickstart-controlplane-0            Ready    master   3d22h   v1.15.3
capi-quickstart-capi-quickstart-worker-85cbf8fd8c-mhrlz   Ready    <none>   3d22h   v1.15.3
capi-quickstart-capi-quickstart-worker-85cbf8fd8c-wjk9h   Ready    <none>   3m8s    v1.15.3

上記のように、capi-quickstart-capi-quickstart-worker-85cbf8fd8c-xxxxxの名前のノードが2台に増えたことが確認できました。

まとめ

Cluster APIを使ってManagement ClusterからKubernetesクラスタを作ってみました。
宣言的APIで動的にワーカーノードを追加することができ、kindよりも柔軟性が高いと感じました。
ただし、Kubeadmの設定があまり隠蔽されないため、YAMLファイルを書く行数はkindより多くなっていると思います。
注意点として、頻繁にkubectlを実行するのですが、今自分がManagement Clusterにkubectlを打っているのか、はたまた作成後のKubernetesクラスタにkubectlを打っているのか、混乱しないように進める必要があると思いました。

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

Ubuntu に Docker + MySQL を入れる

Ubuntu に Docker + MySQL を入れてみる

Ubuntu の環境は既に作成済なのが前提
express と接続して中身見れるようにするのは次回

  • PC環境
    • Vagrant 2.2.7
      • VirtualBox 6.1.2
        • Ubuntu 18.04
          • ここに Docker-CE + MySQL を入れていく
          • 便利なので Docker-Compose も使うよ

Docker をインストールする

参考サイトを見ながらやれば、特に引っ掛からないはず。

Docker インストール前準備

# apt更新
$ sudo apt-get update

# aptがHTTPS経由でリポジトリを使用できるようにする
$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common

# Docker公式GPGキー追加
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# キーを確認
$ sudo apt-key fingerprint 0EBFCD88

# stable設定
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

Docker インストール

# apt更新
$ sudo apt-get update

# 最新バージョンをインストール
$ sudo apt-get install docker-ce

Docker インストール後の話

# docker グループを作成する
$ sudo groupadd docker

# ユーザを docker グループに追加する
$ sudo usermod -aG docker $USER

# 再起動してグループメンバーシップを認識させる
$ sudo reboot
# sudo なしで docker が動くのを確認
$ docker run hello-world

↓こんなのが出ます。タイミングとかで Digest が変わったりとかはするかも。

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f
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-Compose をインストールする

出来るだけ最新の方がいいかも。
最新は、Docker compose release pageにある。
今は、 1.25.4 が最新?

# 最新をダウンロード
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 実行権限を付与
$ sudo chmod +x /usr/local/bin/docker-compose

# インストール確認
$ docker-compose --version

インストール確認すると↓のような出力が出る。

docker-compose version 1.25.4, build 8d51620a

MySQL をインストールする

簡単に試す1

参考サイト->https://qiita.com/astrsk_hori/items/e3d6c237d68be1a6f548
公式のmysqlイメージがあるので、↓これだけで使えるみたい

docker pull mysql
docker run --name mysql -e MYSQL_ROOT_PASSWORD=mysql -d -p 3306:3306 mysql

簡単に試す2

参考サイト->https://budougumi0617.github.io/2018/05/20/create-instant-mysql-by-docker/
途中までは読めたけどまだ分かんないから後でちゃんと読む

簡単だけど簡単じゃない方?

ちゃんと自分でDBを作成してテーブルを作る
参考サイト->https://qiita.com/tiwu_official/items/9ffc8e1fd1173b1a9e40
細かく試した話は後で追記します

参考

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

kubeadmを使用したKubernetes環境構築

Kubermetes1.17環境をkubeadm(環境構築ツール)を用いて作成していく。
過去何度かkubeadmで環境をセットアップしてきたが、躓くことが多いため
備忘録としても活用していきたい。

1.前提となる環境の作成(UbuntuにDockerインストール)
2.MasterNode、Workerノードの構築
3.MasterNodeのセットアップ
4.WorkerNodeのジョイン
5.最後に

1.前提となる環境の作成

Kubernetesをセットアップする前に、ゲストOSの準備やDockerのインストールが必要になるので、それらを準備する。

【Virtualbox】仮想マシン作成

今回、仮想化ソフト:VertualBox、ゲストOS:Ubuntu18.04.3 LTS上でKubernetes環境を構築していく。

まずはホストOSにVirtualBoxをインストールする。
インストール手順は以下を参照
https://eng-entrance.com/virtualbox-install

インストールが完了したら、ゲストOSとなるUbuntuのisoファイルを取得する必要がある。以下のサイトから64-bit PC (AMD64) desktop imageのisoファイルをダウンロードする。
http://releases.ubuntu.com/18.04/

VirtualBoxを起動させて、「新規(N)」をクリックする。
image.png

以下を設定後、作成をクリックする。
・名前:任意(MasterNodeならMaster、WorkerNodeならWorkerなど、、、)
・タイプ(Linux)
・Ubuntu(64-bit)
image.png

「仮想ハードディスクの作成」は設定変更せず「作成」をクリックする。
(今後アプリなどをデプロイしていく場合は容量を追加したほうが◎)
image.png

作成後、以下のように仮想マシンが作成されていることを確認し、
「設定(S)」をクリックする。
image.png

「システム」→「プロセッサー(P)」でプロセッサー数(P)を2に変更する。
image.png

「ストレージ」で「コントローラー:IDE」下の空のディスクにダウンロードした
isoファイルを割り当て、「OK」をクリックする。※「属性」欄のディスクマークをクリックすることで割り当てるファイルを選択することができる。
image.png

ここまでの作業が完了したら、作成した仮想マシンを選択した状態で「起動(T)」をクリックする。※起動したUbuntuに対する初期設定の変更などは特になし。

Dockerインストール

実際に仮想マシンにDockerをインストールする。
まずはお決まりのアップデートを実施する。

$sudo apt update
$sudo apt upgrade

前提ソフトウェアのインストール、docker公式のGPG公開鍵をインストール

$sudo apt install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

aptリポジトリの設定の設定。

$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

docker-ceのインストール。

$sudo apt-get update
$sudo apt-get install docker-ce

インストール完了後、docker runコマンドでhello-worldコンテナを実行し、
以下のように出力されれば問題なし。(実行結果は一部割愛)

$sudo docker run hello-world
nable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f
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:
・・・・

ここまでをMasterNode、WorkerNode合わせて準備しておく。

2.MasterNode、Workerノードの構築

ここからKubermetesをインストールしていくための作業に入る。
また、以下の作業はMasterNode、WorkerNode共通の作業となる。

Kubernetesのキーを取得

$curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

Kubernetesのリポジトリを登録した後、更新を実行する。

$sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
$sudo apt-get update

swapをオフにする。

sudo swapoff -a

各パッケージをインストールする。

apt-get install -y kubelet kubeadm kubectl

パッケージインストール後、/etc/systemd/system/kubelet.service.d/10-kubeadm.confに以下を追記する。

$vi 10-kubeadm.conf
Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=cgroupfs"

上記を実行することで、Cgroup DriverをDockerとkubeletとの間で一致させている。※この作業を実行しないと、MasterNodeのセットアップ時や、WorkerNodeのjoin時にエラーが出力される。(対処にはkubeadmのresetが必要)

3.MasterNodeのセットアップ

MasteNodeの初期化(init)を実行する。
podネットワークプロバイダにflannelを使用するため、 --pod-network-cidr=10.244.0.0/16を指定する。

$ kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=<kube-apiserverがリクエストを待ち受けるIPアドレス>

実行後、以下が表示されればMasterNodeの初期化は成功となる。

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join XXX.XXX.XXX.XXX:6443 --token 7jpywr.uck1h30a1r9rfh2s \
    --discovery-token-ca-cert-hash sha256:18cfec05b9caac750cee77fb162db5f675db3f5ea2031da2030caa209e2eee06

この際、表示されている「kubeadm join~」の値は後程使用するので、メモしておくこと。

以下コマンドを実行する。

$mkdir -p $HOME/.kube
$sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$sudo chown $(id -u):$(id -g) $HOME/.kube/config

MasterNodeの状態を確認する。
(STATUSはNotReadyで問題ない)

$kubectl get nodes

NAME                STATUS   ROLES    AGE    VERSION
master-virtualbox   NotReady    master   5h6m   v1.17.2

flannelのインストール前にiptablesを編集する。

sudo sysctl net.bridge.bridge-nf-call-iptables=1

flannelをインストールする。

$kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

ノードの状態を確認し、「Ready」になっていればセットアップは完了。

$kubectl get nodes

NAME                STATUS   ROLES    AGE    VERSION
master-virtualbox   Ready    master   5h6m   v1.17.2

4.WorkerNodeのジョイン

workerNodeにてMasterNodeのinit時に発行されたコマンド(kubeadm join~)を実行する。

$kubeadm join XXX.XXX.XXX.XXX:6443 --token 7jpywr.uck1h30a1r9rfh2s --discovery-token-ca-cert-hash sha256:18cfec05b9caac750cee77fb162db5f675db3f5ea2031da2030caa209e2eee06

実行後、以下が表示されればMasterNodeへの追加が完了となる。

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

時間が経過すると、トークンが無効になるので以下コマンドで再発行を適宜実施する。

#token
$kubeadm token create
#discovery-token-ca-cert-hash
$openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

MasterNodeでクラスタに参加しているか確認する。

$kubectl get nodes

NAME                STATUS   ROLES    AGE    VERSION
master-virtualbox   Ready    master   5h6m   v1.17.2
node-virtualbox     Ready    <none>   5h4m   v1.17.2

MasterNodeでROLESのラベルを編集する。(MasterNode、WorkerNodeがわかるように)

$kubectl label node node-virtualbox node-role.kubernetes.io/node=
$kubectl get nodes

NAME                STATUS   ROLES    AGE    VERSION
master-virtualbox   Ready    master   5h6m   v1.17.2
node-virtualbox     Ready    node     5h4m   v1.17.2

5.最後に

kubeadmの構築は簡単そうに見えてとにかく穴が多い。。。
(特にMasterの初期化、Workerのjoin)
今後もKubernetesのアップデートの度に何かしら手順が変わったりすると思うので、アンテナを張っておかないと、、、

参考文献

Ubuntu 18.04 LTS にKubernetes環境をインストールする [Master / Worker]

kubeadmでKubernetes1.9.3のClusterを構築したメモ

Ubuntuにdockerをインストールする

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

AWS EC2 Amazon Linux 2 + Docker + Jenkins

概要

AWSのEC2(Amazon Linux2)でDockerでJenkins環境を構築する

Dockerのインストール

$ sudo yum install -y docker
$ sudo service docker start

自動起動を有効にする

$ sudo systemctl enable docker

docker imageのダウンロード

$ sudo docker pull jenkins/jenkins:lts

docker imageの起動

$ sudo docker run -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts

初期パスワード

先ほどのコマンド実行すると↓みたいなのが出力されるのでメモしておく

*************************************************************
*************************************************************
*************************************************************

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

{パスワードがここに表示される}

This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

*************************************************************
*************************************************************
*************************************************************

ブラウザアクセス

http://{IP}:8080/

image.png

ログイン

Administrator passwordに先ほどメモっといたパスワードを入力すれば完了

image.png

以降の作業は参考資料を見てもらえればと思います。

おわり

参考資料

Amazon Linux2にDockerをインストールする

Jenkinsをdocker上に構築

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

Docker 環境で nodemon が watch してくれない問題と対処方法

Web アプリの開発環境を Docker で作っていたところ、nodemon がうまくファイル変更を検出してくれなくて困ったので、そのときのメモ。

マウントしたボリュームだと nodemon が watch してくれない問題

問題を再現するために、以下の3つのファイルを用意する。

ポイントとしては、ホストのディレクトリをコンテナ内にマウントしてそれをコンテナ内の nodemon が watch しているということ。

Dockerfile
FROM node:12

ADD . /app
WORKDIR /app

CMD ["node", "."]
index.js
const http = require('http')

http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' })
  res.end('ok')
}).listen(80)
docker-compose.yml
version: '3'

services:
  app:
    build: .
    ports:
      - 8080:80
    volumes:
      - .:/app
    command: npx nodemon

docker-compose up でコンテナを起動し、Web ブラウザから http://localhost:8080/ にアクセスすると ok と表示されるはず。

この開発用コンテナは nodemon から node プロセスを起動しているので、 index.js が編集された場合には自動で restart してほしい。

しかしこの場合、いくら index.js を編集しても nodemon はその変更を検出してくれない。

Chokidar が Polling するように設定する

nodemon はファイル監視のために内部で Chokidar を利用しており、そのドキュメントにはこのように書いてある。

usePolling (default: false). Whether to use fs.watchFile (backed by polling), or fs.watch. If polling leads to high CPU utilization, consider setting this to false. It is typically necessary to set this to true to successfully watch files over a network, and it may be necessary to successfully watch files in other non-standard situations. Setting to true explicitly on MacOS overrides the useFsEvents default. You may also set the CHOKIDAR_USEPOLLING env variable to true (1) or false (0) in order to override this option.

ネットワーク経由でファイルを監視する場合にはポーリングするように設定する必要があるらしい。

docker-compose.yml
+    environment:
+      CHOKIDAR_USEPOLLING: 1

というわけで環境変数 CHOKIDAR_USEPOLLING=1 を設定した上で再試行したところ、無事にファイル変更を検出してくれるようになった。

めでたしめでたし。

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

MySQL の Docker コンテナで実行した SQL の履歴を保持する

MySQL クライアントの mysql コマンドで実行した SQL は、~/.mysql_hisotry というファイルに保存されるのですが、docker-compose down とかしてコンテナを削除すると、当然このファイルも消えてしまい、履歴が消えてしまいます。
これでは不便なので、ホスト側にファイルを書き込むようにして、毎回これをマウントする方法を考えました。

まずホスト側に .mysql_history を保存するディレクトリを作ります。
名前や場所はなんでも構いません。

$ mkdir -p docker/mysql/history

次にこれをマウントし、環境変数 MYSQL_HISTFILE.mysql_history の保存先を変更します。
マウント先もファイル名も、MYSQL_HISTFILE でパスさえ指定できれば、どこでも構いません。

$ docker run --rm -e MYSQL_HISTFILE=/root/.config/mysql/.mysql_hisotry -v ${PWD}/docker/mysql/history:/root/.config/mysql mysql

docker-compose.yml の場合はこんな感じ。

version: '3'
services:
  mysql:
    container_name: mysql
    image: mysql
    restart: always
    volumes:
      - ./docker/mysql/data:/var/lib/mysql
      - ./docker/mysql/history:/root/.config/mysql  # ← これと
    environment:
      MYSQL_HISTFILE: /root/.config/mysql/.mysql_hisotry  # ← これ

やってみると簡単だけど、ググってもあまり情報が見付からなかったのでメモでした。

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

docker exec で ヒアドキュメントを使いたいんじゃ

タイトルのような状況に遭遇してしまった場合

以下のように実行する。

$ docker exec -i postgres /usr/local/bin/psql db -U db_user <<EOT
select version();
EOT

                                        version
---------------------------------------------------------------------------------------
 PostgreSQL 11.2 on x86_64-pc-linux-musl, compiled by gcc (Alpine 8.2.0) 8.2.0, 64-bit
(1 row)

ヒアドキュメントを入力とするので -t オプション(疑似TTYの割り当て)は不要
つけた場合はエラーになる。

$ docker exec -it postgres /usr/local/bin/psql db -U db_user <<EOT
select version();
EOT
the input device is not a TTY

以下のように sh -c で実行することもできる。

$ docker exec -it postgres sh -c "/usr/local/bin/psql db -U db_user <<EOT
select version();
EOT"

                                        version
---------------------------------------------------------------------------------------
 PostgreSQL 11.2 on x86_64-pc-linux-musl, compiled by gcc (Alpine 8.2.0) 8.2.0, 64-bit
(1 row)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker導入 windows10 pro

Raspberry Piを用いて機械学習モデルを動かしたいと考えています。おそらくDockerを扱うことになるのですが、そもそもDockerで何ができるのか、何が便利なのかを知る必要があるので、実際にDockerを使ってみることで理解を深めようと思います。

※この記事は学習が進み次第再び編集を行います。

Dockerの導入

  • windows10 homeだったのでHyper-Vの仮想化機能のついたwindows10 proにアップグレードしました。13824円かかります。アップグレードは5分もかからず終了!
  • スタートボタンを右クリックしタスクマネージャを開き、パフォーマンスタブで仮想化が有効になっているか確認
  • https://hub.docker.com/editions/community/docker-ce-desktop-windows を開き、ログインしてDockerをダウンロード

Docker基礎

いくつか用語の確認をします。

Dockerイメージ

Dockerコンテナを構成するOSやファイルシステム、実行するアプリケーションや設定をまとめたもので、コンテナを作成するために利用されるテンプレートとなるもの

Dockerコンテナ

Dockerイメージを元に作成され、具現化されたファイルシステムとアプリケーションが実行されている状態

要するにDockerイメージからコンテナが作られ、コンテナの中でOSとして構成されたファイルシステム、アプリが実行されるということです。

主なdocker コマンド

docker container ls -q
コンテナの一覧表示

docker ls
動いているコンテナの確認

docker ls -a
停止しているコンテナの確認

docker rm [コンテナID]
コンテナの削除

docker images
イメージの確認

docker rmi [イメージID]
イメージの削除

docker --help
helpの閲覧

ex. docker image --helpでimageコマンドのhelpが閲覧できる

docker image build -t イメージ名[:タグ名] Dockerfile配置ディレクトリのパス
イメージをビルドする(イメージを構築するという意味) -t (タグ付け)はほぼ必須

docker container ls --filter "[イメージ名]" -q
ancestorで指定したイメージから作られたコンテナを表示することができます

docker stop [コンテナID]
コンテナの停止

docker container ls --filter "[イメージ名]" -q | % { docker stop $_ }
filterでコンテナIDを取得し、パイプラインでdocker stopに渡します

docker run -d -p [イメージ名]
コンテナの実行。-dはdetachの略で、バックグラウンド実行を行う。-pはpublichの略で、portを指定する。左の数字がホストからの接続ポートで、右の数字がコンテナ側への接続ポートを表す

参考文献

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

コード書いたことないPdMやPOに捧ぐ、Rails on Dockerハンズオン vol.2 -Hello, Rails on Docker-

この記事はなにか?
この記事はが社内のプログラミング未経験者、ビギナー向けに開催しているRuby on Rails on Dockerハンズオンの内容をまとめたものです。ていうかこの記事を基にそのままハンズオンします。ハンズオンは
1回の内容は喋りながらやると大体40~50分くらいになっています。お昼休みに有志でやっているからです。
現在進行形なので週1ペースで記事投稿していけるように頑張ります。
ビギナーの方のお役にたったり、同じように有志のハンズオンをしようとしている人の参考になれば幸いです。

他のハンズオンへのリンク
Vol.1 - Introduction -
・ Vol.2 - Hello, Rails on Docker -

$, #, >について
$: ローカルでコマンドを実行するときは、頭に$をつけています。
#: コンテナの中でコマンドを実行するときは、頭に#をつけています。
>: Rails console内でコマンド(Rubyプログラム)を実行するときは、頭に>をつけています。

はじめに

第二回目の今回は、Ruby on RailsをDockerコンテナで起動させるHello worldをやっていきます。

今日のゴール

  • Ruby on Rails on Docker で Hello world する

では早速、Ruby on Rails on Docker で Hello world していきましょう!

Hello, Ruby on Rails on Docker

今回は↓の図のように、Docker 上に Rails アプリケーション用のコンテナと PostgreSQL (database) 用のコンテナを作っていきます。
image.png
まず、作業用のディレクトリを作っておきましょう。

$ mkdir Handson
$ cd Handson

今後、このHandsonディレクトリをホームディレクトリとして話を進めますので、特に指定がない場合、Handsonディレクトリでコマンドを叩いたり、Handsonディレクトリから見た相対パスでファイルを編集していると思ってください。

では早速、Ruby on Rails on Docker な環境を構築するために以下の4つのファイルを作成していきます。

  • Dockerfile: Rails アプリ用の Docker image の元となる設計図
  • Gemfile: Rails アプリに必要なgemを記載するファイル
  • Gemfile.lock: Gemfileによってインストールされたgemのバージョン情報などを管理するファイル
  • docker-compose.yml: 今回のアプリをコンテナ起動させるための Dcoker Compose ファイル

Dockerfile

Dockerfile
FROM ruby:2.7.0-alpine3.11

ENV HOME="/app"
ENV LANG=C.UTF-8
ENV TZ=Asia/Tokyo

WORKDIR $HOME

RUN apk update && \
    apk upgrade && \
    apk add --no-cache \
      gcc \
      g++ \
      libc-dev \
      libxml2-dev \
      linux-headers \
      make \
      nodejs \
      postgresql \
      postgresql-dev \
      tzdata \
      yarn && \
    apk add --virtual build-packs --no-cache \
      build-base \
      curl-dev

COPY Gemfile $HOME
COPY Gemfile.lock $HOME

RUN bundle install && \
    apk del build-packs

COPY . $HOME
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]

Dockerfile は初めて見る人にとっては「なんだこれ?」なものな気がしますが、読んでみると意外とシンプルです。
頭に大文字で書かれているのが命令と呼ばれるものでコマンドみたいなものです。
今回の Dockerfile では以下の命令を利用しています。

  • FROM: ベースイメージを定義する命令です。ruby イメージを指定しているので、元々 Ruby を使用できるイメージの上に Rails を動かす環境を作っていきます。タグの2.7.0-alpine3.11は2020.02.02時点で Ruby の最新バージョンを軽量ディストリビューションとしておなじみの alpine linux のこれまた最新バージョン3.11上で動かしているものを選んでいます。
  • ENV: 環境変数を定義する命令です。
  • WORKDIR: 作業ディレクトリを定義する命令です。ベースイメージ内に該当のディレクトリがない場合は、そのディレクトリを作成することもしてくれます。
  • COPY: ホストのファイルやディレクトリをイメージ内にコピーする命令です。
  • RUN: コマンドを実行する命令です。
  • EXPOSE: コンテナがリッスンするポートを宣言する命令です。 Rails ではデフォルトで 3000 番ポートを使用するので 3000 を指定してあげています。
  • CMD: ソフトウェアを実行するためのコマンドを定義する命令です。コンテナが起動する時に実行されるコマンドといった方がイメージ湧きやすいかもしれません。少し特別な書き方(["xxx", "xxx"]みたいな)をしますが、Rails アプリケーションを起動させるコマンドはrails server -b 0.0.0.0でして、それをCMDの記法で書いています。

あらかた命令と1行1行の内容について述べてしまいましたが、取りこぼしているところをキャッチアップ。

RUN宣言でapk ~と色々書いている9行目からの部分がありますが、apk addは Alpine linux でパッケージをインストールするコマンドです。
apk updateでパッケージリポジトリの最新のインデックス(インストールできる最新バージョンは何か)を取得してきて、apk upgradeですでにインストールしているパッケージで最新版にアップデートできるものをアップデートします。その後、apk addで Rails を起動するのに必要なパッケージをインストールしていきます。--no-cacheオプションはキャッシュを残さないようにするためのオプションです。不要なキャッシュを残さないことでコンテナ自体を軽量に保つことができます。(コンテナは軽量に保っておいた方がダウンロードに時間がかからなかったり、ホストのボリュームを圧迫しないのでよいとされています。)--virtualオプションはそのインストールしたパッケージ達を一つのグループとして名前づけしています。今回の例だとbuild-packsという名前をつけています。ここでインストールしたパッケージは Rails をビルドする上では必要なのですが起動させるためには不要なのであとでapk delで削除するために名前づけしています。

その後、COPY命令でGemfileGemfile.lockをイメージ内にコピーして、bundle installを実行してます。bundle installGemfileの内容に沿ってgemをインストールするコマンドです。Rails 自体もgemでインストールできるのでGemfilerailsを記入しておけばこのbundle installの際にインストールされます。Gemfile.lockはすでにインストール済のgemのバージョンなどを管理して無闇にバージョンアップさせないようにしてくれます。

最後にCOPY . $HOMEでローカルホストのファイルを一式イメージ内にコピーすることで Rails アプリケーションを起動させられる Docker image を作ることができます。

Gemfile

Gemfile
source 'https://rubygems.org'
gem 'rails', '~>6'

Gemfileはかなりシンプルで、インストールするgemのソースとrailsgem をインストールすることを定義しています。Rails は2020.02.02時点で最新バージョンが 6.0.2 なのでまぁメジャーバージョンとして 6 のものをインストールしてくださいというような指定の仕方をしています。
Rails アプリケーションでは最初rails newコマンドでアプリに必要なgemやファイルをインストール・生成するため、初期ではこれほどシンプルなGemfileがあるだけで構わないのです。

Gemfileでバージョンを指定する表現方法はいくつかあります。gemはGitHubなどで公開されていることが多くて大体 README でこう Gemfile に記載してくれと書かれていることが多いのであんまり気にすることはないかもしれませんが一応紹介。

  • gem 'rails', '6.0.0': 絶対 6.0.0 をインストール(バージョンを定義)
  • gem 'rails', >= 6.0.0': 6.0.0 より最新のものをインストール(最低バージョンを定義)
  • gem 'rails', >= 6.0.0', < 6.0.2: 6.0.0 以上 6.0.2 未満のバージョンをインストール(バージョンの範囲を定義)
  • gem 'rails', '~> 6.0.0': 6.0.X のバージョンをインストール(マイナーバージョンを定義)

Gemfile.lock

Gemfile.lockは最初にbundle installされるときに書き込まれるので、最初は空ファイルで問題ありません。

$ touch Gemfile.lock

touchコマンドはファイルの更新日時を現在時刻に更新するためのコマンドですが、ファイルが存在しない場合は空ファイルを生成してくれるのでGemfile.lockを生成するために使いました。

docker-compose.yml

docker-compose.yml
version: '3'

services:
  db:
    image: postgres:12.1-alpine
    environment:
      - TZ=Asia/Tokyo
    volumes:
      - ./tmp/db:/var/lib/postgresql/data

  web:
    build: .
    volumes:
      - .:/app
    ports:
      - 3000:3000
    depends_on:
      - db

まず、サービスとしてdbwebの二つがあることがわかるかと思います。dbは文字通りデータベース用のコンテナ(サービス)、webは Rails アプリケーションを動作させるコンテナ(サービス)です。dbコンテナではimagepostgres:12.1-alpineを指定しています。
docker-compose.ymlについては前回もお話したので、前回お話していない項目を中心にお話します。

  • environment: コンテナを起動する時に環境変数としてセットする。この場合、TZ(タイムゾーン)を東京にしてる。
  • volumes: コンテナからホストのディレクトリをマウントしている。左がホストのパス、右がコンテナ内のパス。ホストのパスはこのdocker-compose.ymlの場所からの相対パスで書いてます。こう書くことで簡単にいえば、ホストのパスとコンテナのパスを同期しているイメージになり、ホストでファイルを編集すればコンテナ内にも反映され、コンテナ内でファイルが編集されればホストのファイルにも反映されるという関係を気づけます。コンテナはステートレスなので一度コンテナを削除して新しくコンテナを起動させた場合、最初のコンテナ(削除したコンテナ)内で変更されたデータは全てなかったことになってしまうのですが、ホストのディレクトリに同期しておくことで次に起動するコンテナもそのディレクトリをマウントするのでデータが永続化されるようになります。
  • build: build: .docker-compose.ymlと同じディレクトリのDockerfileをbuildしたイメージを使ってコンテナを起動するようになります。
  • depends_on: コンテナの依存関係を定義します。今回の場合『webdbに依存している』と定義していることになりますが、これは次の2つが実現されます。
    • docker-compose upした時に、dbコンテナが起動してからwebコンテナを起動する
    • docker-compose up webwebコンテナを起動させようとした場合、dbコンテナも起動させる

Rails アプリケーションを新規作成

まずはrails newコマンドで新規に Rails アプリを作成します。

$ docker-compose run --rm --no-deps web rails new . -fGTd postgresql
...
Webpacker successfully installed ??

いろいろな要素のあるコマンドですね。ちょっと順を追って説明します。
まずこのコマンドの大枠はdocker-compose run [options] <service name> <command>です。今回の例では、

  • [options]: --rm --no-deps
  • <service name>: web
  • <command>: rails new . -fGTd postgresql

となっています。docker-compose rundocker-compose.ymlの定義にそって対象のコンテナを立ち上げてその中でコマンドを実行し、実行後にコンテナを停止するコマンドです。つまり、webコンテナを立ち上げてrails new . -fGTd postgresqlwebコンテナ内で実行してくれます。
--rmオプションはコマンド実行後にコンテナを停止した後に削除までしてくれるオプションです。基本停止したコンテナは不要だと思うのでこのオプションをつけるのがよきかと思います。
--no-depsオプションはdocker-compose.ymldepends_onが定義されていたとしてもそれを無視してdocker-compose runを実行することができます。

次にwebコンテナで実行されるrails new . -fGTd postgresqlを見ていきましょう。
まずrails newは Rails アプリケーションを新規作成するためのコマンドです。.はアプリケーションを作成する場所を指していてカレントディレクトリ(コマンドが実行されたディレクトリ)を示しています。-fGTdはオプションなので一つずつ紐解きます。

  • -f: ファイルの上書きを強制する。Gemfileなどに上書きが走りますがいちいち Yes or No を聞かれないようにするためにつけています。
  • -G: Gitの初期設定をスキップします。Rails 6 からなんかこのオプションをつけないとまともにrails newできなかったのでつけてます。
  • -T: minitestという Rails でデフォルトでインストールされるテストフレームワークのインストールをスキップします。僕はRSpecというテストフレームワークをよく使っているのでこのオプションをつけて無駄にminitestがインストールされないようにしています。
  • -d: -d <database name>で利用するデータベースを指定します。今回はpostgresqlを指定。

Rails アプリケーションの新規作成ができたら一度イメージをビルドしておきましょう。

$ docker-compose build
...
Successfully tagged handson_web:latest

docker-compose buildコマンドはdocker-compose.ymlDockerfileからのビルドが必要なサービスのイメージビルドをすべて実行してくれます。今回はdbは DockerHub のイメージを使っているのでwebのみがビルドが必要なサービスとしてビルドされます。

DBの接続設定

ビルドが終わったら、Rails アプリケーションの DB 接続設定をコーディングしていきます。 DB の接続設定はconfig/database.ymlに記載します。 Rails では設定系のファイルはconfigディレクトリに格納されています。

config/database.yml
...
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
...

hostusernamepasswordがデフォルトから新たに追加した項目です。
hostはDBのホスト名です。今 Rails アプリが稼働しているwebコンテナはdocker-compose.ymlが作る Docker ネットワークの中にいます。この中ではサービス名で名前解決してコンテナが相互に接続することができます。つまりhostとしてdbを設定することでdocker-compose.ymldbのサービス名で定義されたコンテナに接続できるようになるのです。
usernamepasswordは何の値なのでしょうか?これはdbコンテナのイメージで指定したpostgresのデフォルト値です。passwordは同じホストからのアクセスであれば省略が可能になっています。postgresイメージのusernamepasswordはそれぞれPOSTGRES_USERPOSTGRES_PASSWORDの環境変数で定義することもできます。

データベースの設定はここまでです。このデフォルトの設定値が開発環境(development)、テスト環境(test)の設定値として反映されるようになっています。

データベースを作成する

データベースの接続設定を定義したので、データベースを実際に作成していきます。
Rails ではデフォルトで本番環境(production)、開発環境(development)、テスト環境(test)の3つの環境(environment)が用意されています。特別に環境を指定しない場合、開発環境で挙動するようになっています。
データベースの作成はrails db:createコマンドを使いますが、このコマンドは開発環境とテスト環境用にデータベースを作成してくれます。本番環境用のデータベースを作成する場合は、RAILS_ENV=productionをオプションとしてつけます。
今回はまず開発環境向けにデータベースの作成を行いたいので、以下のコマンドを実行します。

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

Hello Ruby on Rails on Docker!!

ここまでで Hello world に必要な作業は全て完了しました。
コンテナを立ち上げて Hello world ページが表示されることを確認しましょう。

$ docker-compose up -d

Rails アプリは少し起動に時間がかかります。すぐにhttp://localhost:3000にアクセスしてもまだアプリケーションが起動していないこともありますので、その場合はdocker-compose logsコマンドを使ってアプリケーションの起動状態を確認してみましょう。

$ docker-compose logs -f

-fオプションはログの変化をリアルタイムでコンソールに表示するためのオプションです。Rails アプリが起動した場合

web_1 | Use Ctrl+C to stop

というログが表示されます。この表示を確認したらCtrl+Cdocker-compose logsから抜け出しましょう。

では、http://localhost:3000にアクセスしてみましょう!
image.png
このようなページが表示されたでしょうか?このページが Rails アプリケーションの第一歩、つまり Hello world です。おめでとうございます!これでもう『Rails は Hello world までならやったことあります』と自慢することができます!

ここまでできたら後片付けをしておきましょう。
このままではコンテナが起動しっぱなしになってしまうので、最後にコンテナを停止させておきます。

$ docker-compose down

これでコンテナを停止させたので、http://localhost:3000にアクセスしても先ほどのページは表示されなくなっていることでしょう。

まとめ

今回は、Dockerfiledocker-compose.ymlなどのファイルを作成し、Rails アプリケーションを稼働させられる Docker イメージ、Docker コンテナを作成してみました。
さらに、Rails アプリを新規作成して Hello world に成功しました!
まだまだアプリケーション開発のほんの入り口ですが、Docker を使って Web アプリを起動させることができただけでもかなり感動があると思いますし、ここまでさほど大変ではないことも感じてもらえたかなと思います。これこそが Rails や Docker の偉大なところですね。

次回は、scaffoldという Rails の便利機能を使って、サンプル Web アプリケーションを作ってみようと思います。このscaffoldで作成できるアプリケーションが Rails の基本的なアプリケーションの形になりまして、その中には Rails アプリケーションを語る上では避けられないRESTfulMVCの要素が詰まっていますので、その辺りも合わせて学んでいけるようにしようと思います。

では、次回も乞うご期待!ここまでお読みいただきありがとうございました!

Reference

P.S. 間違っているところ、抜けているところ、説明の仕方を変えるとよりわかりやすくなるところなどありましたら、優しくアドバイスいただけると助かります。

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

コード書いたことないPdMやPOに捧ぐ、Ruby on Rails on Dockerハンズオン vol.2 -Hello, Ruby on Rails on Docker-

この記事はなにか?
この記事はが社内のプログラミング未経験者、ビギナー向けに開催しているRuby on Rails on Dockerハンズオンの内容をまとめたものです。ていうかこの記事を基にそのままハンズオンします。ハンズオンは
1回の内容は喋りながらやると大体40~50分くらいになっています。お昼休みに有志でやっているからです。
現在進行形なので週1ペースで記事投稿していけるように頑張ります。
ビギナーの方のお役にたったり、同じように有志のハンズオンをしようとしている人の参考になれば幸いです。

他のハンズオンへのリンク
- Ruby on Rails on Dockerハンズオン vol.1 -Introduction-

$, #, >について
$: ローカルでコマンドを実行するときは、頭に$をつけています。
#: コンテナの中でコマンドを実行するときは、頭に#をつけています。
>: Rails console内でコマンド(Rubyプログラム)を実行するときは、頭に>をつけています。

はじめに

第二回目の今回は、Ruby on RailsをDockerコンテナで起動させるHello worldをやっていきます。

今日のゴール

  • Ruby on Rails on Docker で Hello world する

では早速、Ruby on Rails on Docker で Hello world していきましょう!

Hello, Ruby on Rails on Docker

今回は↓の図のように、Docker 上に Rails アプリケーション用のコンテナと PostgreSQL (database) 用のコンテナを作っていきます。
image.png
まず、作業用のディレクトリを作っておきましょう。

$ mkdir Handson
$ cd Handson

今後、このHandsonディレクトリをホームディレクトリとして話を進めますので、特に指定がない場合、Handsonディレクトリでコマンドを叩いたり、Handsonディレクトリから見た相対パスでファイルを編集していると思ってください。

では早速、Ruby on Rails on Docker な環境を構築するために以下の4つのファイルを作成していきます。

  • Dockerfile: Rails アプリ用の Docker image の元となる設計図
  • Gemfile: Rails アプリに必要なgemを記載するファイル
  • Gemfile.lock: Gemfileによってインストールされたgemのバージョン情報などを管理するファイル
  • docker-compose.yml: 今回のアプリをコンテナ起動させるための Dcoker Compose ファイル

Dockerfile

Dockerfile
FROM ruby:2.7.0-alpine3.11

ENV HOME="/app"
ENV LANG=C.UTF-8
ENV TZ=Asia/Tokyo

WORKDIR $HOME

RUN apk update && \
    apk upgrade && \
    apk add --no-cache \
      gcc \
      g++ \
      libc-dev \
      libxml2-dev \
      linux-headers \
      make \
      nodejs \
      postgresql \
      postgresql-dev \
      tzdata \
      yarn && \
    apk add --virtual build-packs --no-cache \
      build-base \
      curl-dev

COPY Gemfile $HOME
COPY Gemfile.lock $HOME

RUN bundle install && \
    apk del build-packs

COPY . $HOME
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]

Dockerfile は初めて見る人にとっては「なんだこれ?」なものな気がしますが、読んでみると意外とシンプルです。
頭に大文字で書かれているのが命令と呼ばれるものでコマンドみたいなものです。
今回の Dockerfile では以下の命令を利用しています。

  • FROM: ベースイメージを定義する命令です。ruby イメージを指定しているので、元々 Ruby を使用できるイメージの上に Rails を動かす環境を作っていきます。タグの2.7.0-alpine3.11は2020.02.02時点で Ruby の最新バージョンを軽量ディストリビューションとしておなじみの alpine linux のこれまた最新バージョン3.11上で動かしているものを選んでいます。
  • ENV: 環境変数を定義する命令です。
  • WORKDIR: 作業ディレクトリを定義する命令です。ベースイメージ内に該当のディレクトリがない場合は、そのディレクトリを作成することもしてくれます。
  • COPY: ホストのファイルやディレクトリをイメージ内にコピーする命令です。
  • RUN: コマンドを実行する命令です。
  • EXPOSE: コンテナがリッスンするポートを宣言する命令です。 Rails ではデフォルトで 3000 番ポートを使用するので 3000 を指定してあげています。
  • CMD: ソフトウェアを実行するためのコマンドを定義する命令です。コンテナが起動する時に実行されるコマンドといった方がイメージ湧きやすいかもしれません。少し特別な書き方(["xxx", "xxx"]みたいな)をしますが、Rails アプリケーションを起動させるコマンドはrails server -b 0.0.0.0でして、それをCMDの記法で書いています。

あらかた命令と1行1行の内容について述べてしまいましたが、取りこぼしているところをキャッチアップ。

RUN宣言でapk ~と色々書いている9行目からの部分がありますが、apk addは Alpine linux でパッケージをインストールするコマンドです。
apk updateでパッケージリポジトリの最新のインデックス(インストールできる最新バージョンは何か)を取得してきて、apk upgradeですでにインストールしているパッケージで最新版にアップデートできるものをアップデートします。その後、apk addで Rails を起動するのに必要なパッケージをインストールしていきます。--no-cacheオプションはキャッシュを残さないようにするためのオプションです。不要なキャッシュを残さないことでコンテナ自体を軽量に保つことができます。(コンテナは軽量に保っておいた方がダウンロードに時間がかからなかったり、ホストのボリュームを圧迫しないのでよいとされています。)--virtualオプションはそのインストールしたパッケージ達を一つのグループとして名前づけしています。今回の例だとbuild-packsという名前をつけています。ここでインストールしたパッケージは Rails をビルドする上では必要なのですが起動させるためには不要なのであとでapk delで削除するために名前づけしています。

その後、COPY命令でGemfileGemfile.lockをイメージ内にコピーして、bundle installを実行してます。bundle installGemfileの内容に沿ってgemをインストールするコマンドです。Rails 自体もgemでインストールできるのでGemfilerailsを記入しておけばこのbundle installの際にインストールされます。Gemfile.lockはすでにインストール済のgemのバージョンなどを管理して無闇にバージョンアップさせないようにしてくれます。

最後にCOPY . $HOMEでローカルホストのファイルを一式イメージ内にコピーすることで Rails アプリケーションを起動させられる Docker image を作ることができます。

Gemfile

Gemfile
source 'https://rubygems.org'
gem 'rails', '~>6'

Gemfileはかなりシンプルで、インストールするgemのソースとrailsgem をインストールすることを定義しています。Rails は2020.02.02時点で最新バージョンが 6.0.2 なのでまぁメジャーバージョンとして 6 のものをインストールしてくださいというような指定の仕方をしています。
Rails アプリケーションでは最初rails newコマンドでアプリに必要なgemやファイルをインストール・生成するため、初期ではこれほどシンプルなGemfileがあるだけで構わないのです。

Gemfileでバージョンを指定する表現方法はいくつかあります。gemはGitHubなどで公開されていることが多くて大体 README でこう Gemfile に記載してくれと書かれていることが多いのであんまり気にすることはないかもしれませんが一応紹介。

  • gem 'rails', '6.0.0': 絶対 6.0.0 をインストール(バージョンを定義)
  • gem 'rails', >= 6.0.0': 6.0.0 より最新のものをインストール(最低バージョンを定義)
  • gem 'rails', >= 6.0.0', < 6.0.2: 6.0.0 以上 6.0.2 未満のバージョンをインストール(バージョンの範囲を定義)
  • gem 'rails', '~> 6.0.0': 6.0.X のバージョンをインストール(マイナーバージョンを定義)

Gemfile.lock

Gemfile.lockは最初にbundle installされるときに書き込まれるので、最初は空ファイルで問題ありません。

$ touch Gemfile.lock

touchコマンドはファイルの更新日時を現在時刻に更新するためのコマンドですが、ファイルが存在しない場合は空ファイルを生成してくれるのでGemfile.lockを生成するために使いました。

docker-compose.yml

docker-compose.yml
version: '3'

services:
  db:
    image: postgres:12.1-alpine
    environment:
      - TZ=Asia/Tokyo
    volumes:
      - ./tmp/db:/var/lib/postgresql/data

  web:
    build: .
    volumes:
      - .:/app
    ports:
      - 3000:3000
    depends_on:
      - db

まず、サービスとしてdbwebの二つがあることがわかるかと思います。dbは文字通りデータベース用のコンテナ(サービス)、webは Rails アプリケーションを動作させるコンテナ(サービス)です。dbコンテナではimagepostgres:12.1-alpineを指定しています。
docker-compose.ymlについては前回もお話したので、前回お話していない項目を中心にお話します。

  • environment: コンテナを起動する時に環境変数としてセットする。この場合、TZ(タイムゾーン)を東京にしてる。
  • volumes: コンテナからホストのディレクトリをマウントしている。左がホストのパス、右がコンテナ内のパス。ホストのパスはこのdocker-compose.ymlの場所からの相対パスで書いてます。こう書くことで簡単にいえば、ホストのパスとコンテナのパスを同期しているイメージになり、ホストでファイルを編集すればコンテナ内にも反映され、コンテナ内でファイルが編集されればホストのファイルにも反映されるという関係を気づけます。コンテナはステートレスなので一度コンテナを削除して新しくコンテナを起動させた場合、最初のコンテナ(削除したコンテナ)内で変更されたデータは全てなかったことになってしまうのですが、ホストのディレクトリに同期しておくことで次に起動するコンテナもそのディレクトリをマウントするのでデータが永続化されるようになります。
  • build: build: .docker-compose.ymlと同じディレクトリのDockerfileをbuildしたイメージを使ってコンテナを起動するようになります。
  • depends_on: コンテナの依存関係を定義します。今回の場合『webdbに依存している』と定義していることになりますが、これは次の2つが実現されます。
    • docker-compose upした時に、dbコンテナが起動してからwebコンテナを起動する
    • docker-compose up webwebコンテナを起動させようとした場合、dbコンテナも起動させる

Rails アプリケーションを新規作成

まずはrails newコマンドで新規に Rails アプリを作成します。

$ docker-compose run --rm --no-deps web rails new . -fGTd postgresql
...
Webpacker successfully installed ??

いろいろな要素のあるコマンドですね。ちょっと順を追って説明します。
まずこのコマンドの大枠はdocker-compose run [options] <service name> <command>です。今回の例では、

  • [options]: --rm --no-deps
  • <service name>: web
  • <command>: rails new . -fGTd postgresql

となっています。docker-compose rundocker-compose.ymlの定義にそって対象のコンテナを立ち上げてその中でコマンドを実行し、実行後にコンテナを停止するコマンドです。つまり、webコンテナを立ち上げてrails new . -fGTd postgresqlwebコンテナ内で実行してくれます。
--rmオプションはコマンド実行後にコンテナを停止した後に削除までしてくれるオプションです。基本停止したコンテナは不要だと思うのでこのオプションをつけるのがよきかと思います。
--no-depsオプションはdocker-compose.ymldepends_onが定義されていたとしてもそれを無視してdocker-compose runを実行することができます。

次にwebコンテナで実行されるrails new . -fGTd postgresqlを見ていきましょう。
まずrails newは Rails アプリケーションを新規作成するためのコマンドです。.はアプリケーションを作成する場所を指していてカレントディレクトリ(コマンドが実行されたディレクトリ)を示しています。-fGTdはオプションなので一つずつ紐解きます。

  • -f: ファイルの上書きを強制する。Gemfileなどに上書きが走りますがいちいち Yes or No を聞かれないようにするためにつけています。
  • -G: Gitの初期設定をスキップします。Rails 6 からなんかこのオプションをつけないとまともにrails newできなかったのでつけてます。
  • -T: minitestという Rails でデフォルトでインストールされるテストフレームワークのインストールをスキップします。僕はRSpecというテストフレームワークをよく使っているのでこのオプションをつけて無駄にminitestがインストールされないようにしています。
  • -d: -d <database name>で利用するデータベースを指定します。今回はpostgresqlを指定。

Rails アプリケーションの新規作成ができたら一度イメージをビルドしておきましょう。

$ docker-compose build
...
Successfully tagged handson_web:latest

docker-compose buildコマンドはdocker-compose.ymlDockerfileからのビルドが必要なサービスのイメージビルドをすべて実行してくれます。今回はdbは DockerHub のイメージを使っているのでwebのみがビルドが必要なサービスとしてビルドされます。

DBの接続設定

ビルドが終わったら、Rails アプリケーションの DB 接続設定をコーディングしていきます。 DB の接続設定はconfig/database.ymlに記載します。 Rails では設定系のファイルはconfigディレクトリに格納されています。

config/database.yml
...
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
...

hostusernamepasswordがデフォルトから新たに追加した項目です。
hostはDBのホスト名です。今 Rails アプリが稼働しているwebコンテナはdocker-compose.ymlが作る Docker ネットワークの中にいます。この中ではサービス名で名前解決してコンテナが相互に接続することができます。つまりhostとしてdbを設定することでdocker-compose.ymldbのサービス名で定義されたコンテナに接続できるようになるのです。
usernamepasswordは何の値なのでしょうか?これはdbコンテナのイメージで指定したpostgresのデフォルト値です。passwordは同じホストからのアクセスであれば省略が可能になっています。postgresイメージのusernamepasswordはそれぞれPOSTGRES_USERPOSTGRES_PASSWORDの環境変数で定義することもできます。

データベースの設定はここまでです。このデフォルトの設定値が開発環境(development)、テスト環境(test)の設定値として反映されるようになっています。

データベースを作成する

データベースの接続設定を定義したので、データベースを実際に作成していきます。
Rails ではデフォルトで本番環境(production)、開発環境(development)、テスト環境(test)の3つの環境(environment)が用意されています。特別に環境を指定しない場合、開発環境で挙動するようになっています。
データベースの作成はrails db:createコマンドを使いますが、このコマンドは開発環境とテスト環境用にデータベースを作成してくれます。本番環境用のデータベースを作成する場合は、RAILS_ENV=productionをオプションとしてつけます。
今回はまず開発環境向けにデータベースの作成を行いたいので、以下のコマンドを実行します。

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

Hello Ruby on Rails on Docker!!

ここまでで Hello world に必要な作業は全て完了しました。
コンテナを立ち上げて Hello world ページが表示されることを確認しましょう。

$ docker-compose up -d

Rails アプリは少し起動に時間がかかります。すぐにhttp://localhost:3000にアクセスしてもまだアプリケーションが起動していないこともありますので、その場合はdocker-compose logsコマンドを使ってアプリケーションの起動状態を確認してみましょう。

$ docker-compose logs -f

-fオプションはログの変化をリアルタイムでコンソールに表示するためのオプションです。Rails アプリが起動した場合

web_1 | Use Ctrl+C to stop

というログが表示されます。この表示を確認したらCtrl+Cdocker-compose logsから抜け出しましょう。

では、http://localhost:3000にアクセスしてみましょう!
image.png
このようなページが表示されたでしょうか?このページが Rails アプリケーションの第一歩、つまり Hello world です。おめでとうございます!これでもう『Rails は Hello world までならやったことあります』と自慢することができます!

ここまでできたら後片付けをしておきましょう。
このままではコンテナが起動しっぱなしになってしまうので、最後にコンテナを停止させておきます。

$ docker-compose down

これでコンテナを停止させたので、http://localhost:3000にアクセスしても先ほどのページは表示されなくなっていることでしょう。

まとめ

今回は、Dockerfiledocker-compose.ymlなどのファイルを作成し、Rails アプリケーションを稼働させられる Docker イメージ、Docker コンテナを作成してみました。
さらに、Rails アプリを新規作成して Hello world に成功しました!
まだまだアプリケーション開発のほんの入り口ですが、Docker を使って Web アプリを起動させることができただけでもかなり感動があると思いますし、ここまでさほど大変ではないことも感じてもらえたかなと思います。これこそが Rails や Docker の偉大なところですね。

次回は、scaffoldという Rails の便利機能を使って、サンプル Web アプリケーションを作ってみようと思います。このscaffoldで作成できるアプリケーションが Rails の基本的なアプリケーションの形になりまして、その中には Rails アプリケーションを語る上では避けられないRESTfulMVCの要素が詰まっていますので、その辺りも合わせて学んでいけるようにしようと思います。

では、次回も乞うご期待!ここまでお読みいただきありがとうございました!

Reference

P.S. 間違っているところ、抜けているところ、説明の仕方を変えるとよりわかりやすくなるところなどありましたら、優しくアドバイスいただけると助かります。

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

Centos8にDockerを入れてみる

本格的にCentos8を使い始めたので、いろいろ導入してみたことを記載します。
今回はDockerについてです。

公式のインストール手順はこちらから。

ちなみに公式が公開している手順はCentos7ベースです。
私が試してみた際には2か所ほど引っ掛かりました。

Docker インストール

古いパッケージの削除

新規インストールの場合は飛ばしてもよいかもしれません。

$ sudo dnf remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

一致した引数がありません: docker
一致した引数がありません: docker-client
一致した引数がありません: docker-client-latest
一致した引数がありません: docker-common
一致した引数がありません: docker-latest
一致した引数がありません: docker-latest-logrotate
一致した引数がありません: docker-logrotate
一致した引数がありません: docker-engine
削除対象のパッケージはありません。
依存関係が解決しました。
行うべきことはありません。
完了しました!

必要パッケージをインストールします。

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

CentOS-8 - AppStream                                                               3.9 MB/s | 6.0 MB     00:01
CentOS-8 - Base                                                                    4.0 MB/s | 4.0 MB     00:01
CentOS-8 - Extras                                                                  2.5 kB/s | 2.1 kB     00:00
Extra Packages for Enterprise Linux Modular 8 - x86_64                              24 kB/s |  21 kB     00:00
Extra Packages for Enterprise Linux 8 - x86_64                                     4.0 MB/s | 5.5 MB     00:01
Remi's Modular repository for Enterprise Linux 8 - x86_64                           87 kB/s | 531 kB     00:06
Safe Remi's RPM repository for Enterprise Linux 8 - x86_64                         142 kB/s | 1.4 MB     00:10
パッケージ yum-utils-4.0.8-3.el8.noarch は既にインストールされています。
パッケージ device-mapper-persistent-data-0.8.5-2.el8.x86_64 は既にインストールされています。
パッケージ lvm2-8:2.03.05-5.el8.0.1.x86_64 は既にインストールされています。
依存関係が解決しました。
行うべきことはありません。
完了しました!

リポジトリを追加します。

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

Adding repo from: https://download.docker.com/linux/centos/docker-ce.repo

Dockerをインストールします。
そして引っ掛かりました。

$ sudo dnf install docker-ce docker-ce-cli containerd.io
CentOS-8 - AppStream                                                                11 kB/s | 4.3 kB     00:00
CentOS-8 - Base                                                                    5.1 kB/s | 3.8 kB     00:00
CentOS-8 - Extras                                                                  3.7 kB/s | 1.5 kB     00:00
Docker CE Stable - x86_64                                                           67 kB/s |  21 kB     00:00
Extra Packages for Enterprise Linux Modular 8 - x86_64                             9.0 kB/s | 8.7 kB     00:00
Extra Packages for Enterprise Linux 8 - x86_64                                      14 kB/s | 9.3 kB     00:00
Remi's Modular repository for Enterprise Linux 8 - x86_64                          3.2 kB/s | 3.5 kB     00:01
Safe Remi's RPM repository for Enterprise Linux 8 - x86_64                         2.9 kB/s | 3.0 kB     00:01
エラー:
 問題: package docker-ce-3:19.03.5-3.el7.x86_64 requires containerd.io >= 1.2.2-3, but none of the providers can be
 installed
  - cannot install the best candidate for the job
  - package containerd.io-1.2.10-3.2.el7.x86_64 is excluded
  - package containerd.io-1.2.2-3.3.el7.x86_64 is excluded
  - package containerd.io-1.2.2-3.el7.x86_64 is excluded
  - package containerd.io-1.2.4-3.1.el7.x86_64 is excluded
  - package containerd.io-1.2.5-3.1.el7.x86_64 is excluded
  - package containerd.io-1.2.6-3.3.el7.x86_64 is excluded
(インストール不可のパッケージをスキップするには、'--skip-broken' を追加してみてください または、'--nobest' を追加し
て、最適候補のパッケージのみを使用しないでください)

どうやらpackage containerd.ioで列挙されたバージョンが必要なのに、インストールができなかったようです。

$ sudo dnf search --repo docker-ce-stable containerd.io
========================================== 名前 完全一致: containerd.io ===========================================
containerd.io.x86_64 : An industry-standard container runtime

検索してみるとパッケージはありました。

$ dnf info --repo docker-ce-stable containerd.io
利用可能なパッケージ
名前         : containerd.io
バージョン   : 1.2.10
リリース     : 3.2.el7
Arch         : x86_64
サイズ       : 23 M
ソース       : containerd.io-1.2.10-3.2.el7.src.rpm
リポジトリー : docker-ce-stable
概要         : An industry-standard container runtime
URL          : https://containerd.io
ライセンス   : ASL 2.0
説明         : containerd is an industry-standard container runtime with an emphasis on
             : simplicity, robustness and portability. It is available as a daemon for Linux
             : and Windows, which can manage the complete container lifecycle of its host
             : system: image transfer and storage, container execution and supervision,
             : low-level storage and network attachments, etc.

infoで見てもバージョンに問題はなさそうなんですが。。。

$ sudo dnf --showduplicates search containerd.io
========================================== 名前 完全一致: containerd.io ===========================================
containerd.io-1.2.0-1.2.beta.2.el7.x86_64 : An industry-standard container runtime
containerd.io-1.2.0-2.0.rc.0.1.el7.x86_64 : An industry-standard container runtime
containerd.io-1.2.0-2.2.rc.2.1.el7.x86_64 : An industry-standard container runtime
containerd.io-1.2.0-3.el7.x86_64 : An industry-standard container runtime

インストール可能な全バージョンを検索してみたら、containerd.io-1.2.0 しかありませんでした。
infoで出たバージョンは何だったんだろう。。。?

仕方がないので、ここから最新パッケージを落としてきてインストールします。
参考:CentOS8にDockerを入れる

そしてまた引っ掛かりました。

$ wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.10-3.2.el7.x86_64.rpm
$ sudo rpm -ivh containerd.io-1.2.10-3.2.el7.x86_64.rpm
error: Failed dependencies:
        container-selinux >= 2:2.74 is needed by containerd.io-1.2.10-3.2.el7.x86_64

container-selinux が必要ってことですね。
今のバージョンは。。。?

$ sudo rpm -qa | grep container-selinux
$ 

oh...そもそもパッケージが入っていませんでした。

containerd.ioの二の舞にならないよう、念のため全バージョンを確認しておきましょう。

$ sudo dnf --showduplicates search container-selinux
======================================== 名前 完全一致: container-selinux =========================================
container-selinux-2:2.107-2.module_el8.1.0+237+63e26edc.noarch : SELinux policies for container runtimes

バージョン問題はクリアしていますね。
インストールしましょう。

$ sudo dnf install container-selinux
依存関係が解決しました。
===================================================================================================================
 パッケージ                Arch           バージョン                                       リポジトリー      サイズ
===================================================================================================================
インストール:
 container-selinux         noarch         2:2.107-2.module_el8.1.0+237+63e26edc            AppStream          44 k
モジュールストリームの有効化:
 container-tools                          rhel8

トランザクションの概要
===================================================================================================================
インストール  1 パッケージ

ダウンロードサイズの合計: 44 k
インストール済みのサイズ: 40 k
これでよろしいですか? [y/N]: y
パッケージのダウンロード:
container-selinux-2.107-2.module_el8.1.0+237+63e26edc.noarch.rpm                    26 kB/s |  44 kB     00:01
-------------------------------------------------------------------------------------------------------------------
合計                                                                                19 kB/s |  44 kB     00:02
トランザクションの確認を実行中
トランザクションの確認に成功しました。
トランザクションのテストを実行中
トランザクションのテストに成功しました。
トランザクションを実行中
  準備             :                                                                                           1/1
  インストール中   : container-selinux-2:2.107-2.module_el8.1.0+237+63e26edc.noarch                            1/1
  scriptletの実行中: container-selinux-2:2.107-2.module_el8.1.0+237+63e26edc.noarch                            1/1
  検証             : container-selinux-2:2.107-2.module_el8.1.0+237+63e26edc.noarch                            1/1

インストール済み:
  container-selinux-2:2.107-2.module_el8.1.0+237+63e26edc.noarch

完了しました!

無事にインストールできました。
改めてcontainerd.ioをインストールします。

$ sudo rpm -ivh containerd.io-1.2.10-3.2.el7.x86_64.rpm
warning: containerd.io-1.2.10-3.2.el7.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 621e9f35: NOKEY
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:containerd.io-1.2.10-3.2.el7     ################################# [100%]

こちらも無事にインストールできました。

ようやくDockerがインストールできます!

$ sudo dnf install docker-ce docker-ce-cli
依存関係が解決しました。
===================================================================================================================
 パッケージ                 アーキテクチャー    バージョン                     リポジトリー                  サイズ
===================================================================================================================
インストール:
 docker-ce                  x86_64              3:19.03.5-3.el7                docker-ce-stable               24 M
 docker-ce-cli              x86_64              1:19.03.5-3.el7                docker-ce-stable               39 M
依存関係のインストール:
 libcgroup                  x86_64              0.41-19.el8                    BaseOS                         70 k

トランザクションの概要
===================================================================================================================
インストール  3 パッケージ

ダウンロードサイズの合計: 64 M
インストール済みのサイズ: 273 M
これでよろしいですか? [y/N]: y
パッケージのダウンロード:
(1/3): libcgroup-0.41-19.el8.x86_64.rpm                                             54 kB/s |  70 kB     00:01
(2/3): docker-ce-19.03.5-3.el7.x86_64.rpm                                           11 MB/s |  24 MB     00:02
(3/3): docker-ce-cli-19.03.5-3.el7.x86_64.rpm                                       11 MB/s |  39 MB     00:03
-------------------------------------------------------------------------------------------------------------------
合計                                                                                15 MB/s |  64 MB     00:04
warning: /var/cache/dnf/docker-ce-stable-091d8a9c23201250/packages/docker-ce-19.03.5-3.el7.x86_64.rpm: Header V4 RS
A/SHA512 Signature, key ID 621e9f35: NOKEY
Docker CE Stable - x86_64                                                           13 kB/s | 1.6 kB     00:00
GPG 鍵 0x621E9F35 をインポート中:
 Userid     : "Docker Release (CE rpm) <docker@docker.com>"
 Fingerprint: 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35
 From       : https://download.docker.com/linux/centos/gpg
これでよろしいですか? [y/N]: y
鍵のインポートに成功しました
トランザクションの確認を実行中
トランザクションの確認に成功しました。
トランザクションのテストを実行中
トランザクションのテストに成功しました。
トランザクションを実行中
  準備             :                                                                                           1/1
  インストール中   : docker-ce-cli-1:19.03.5-3.el7.x86_64                                                      1/3
  scriptletの実行中: docker-ce-cli-1:19.03.5-3.el7.x86_64                                                      1/3
  scriptletの実行中: libcgroup-0.41-19.el8.x86_64                                                              2/3
  インストール中   : libcgroup-0.41-19.el8.x86_64                                                              2/3
  scriptletの実行中: libcgroup-0.41-19.el8.x86_64                                                              2/3
  インストール中   : docker-ce-3:19.03.5-3.el7.x86_64                                                          3/3
  scriptletの実行中: docker-ce-3:19.03.5-3.el7.x86_64                                                          3/3
  検証             : libcgroup-0.41-19.el8.x86_64                                                              1/3
  検証             : docker-ce-3:19.03.5-3.el7.x86_64                                                          2/3
  検証             : docker-ce-cli-1:19.03.5-3.el7.x86_64                                                      3/3

インストール済み:
  docker-ce-3:19.03.5-3.el7.x86_64      docker-ce-cli-1:19.03.5-3.el7.x86_64      libcgroup-0.41-19.el8.x86_64

完了しました!

さて、Dockerを起動してみましょう。

$ sudo systemctl start docker
$ sudo systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
   Active: active (running) since Tue 2020-02-04 11:37:29 JST; 5s ago
     Docs: https://docs.docker.com
 Main PID: 14218 (dockerd)
    Tasks: 10
   Memory: 44.6M
   CGroup: /system.slice/docker.service
           └─14218 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

 2月 04 11:37:29 server1 dockerd[14218]: time="2020-02-04T11:37:29.169376623+09:00" level=info msg="ClientConn swi>
 2月 04 11:37:29 server1 dockerd[14218]: time="2020-02-04T11:37:29.194751667+09:00" level=warning msg="Your kernel>
 2月 04 11:37:29 server1 dockerd[14218]: time="2020-02-04T11:37:29.194778024+09:00" level=warning msg="Your kernel>
 2月 04 11:37:29 server1 dockerd[14218]: time="2020-02-04T11:37:29.194932968+09:00" level=info msg="Loading contai>
 2月 04 11:37:29 server1 dockerd[14218]: time="2020-02-04T11:37:29.410006453+09:00" level=info msg="Default bridge>
 2月 04 11:37:29 server1 dockerd[14218]: time="2020-02-04T11:37:29.504908668+09:00" level=info msg="Loading contai>
 2月 04 11:37:29 server1 dockerd[14218]: time="2020-02-04T11:37:29.522814914+09:00" level=info msg="Docker daemon">
 2月 04 11:37:29 server1 dockerd[14218]: time="2020-02-04T11:37:29.523082762+09:00" level=info msg="Daemon has com>
 2月 04 11:37:29 server1 dockerd[14218]: time="2020-02-04T11:37:29.550752482+09:00" level=info msg="API listen on >
 2月 04 11:37:29 server1 systemd[1]: Started Docker Application Container Engine.

問題なく動いているようです。
あとは自動起動の設定を忘れずに実施すれば完了ですね。

$ sudo systemctl enable docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.

お疲れ様でした。

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

Matlab 9.6 R2019a 稼働RuntimeのDockerイメージビルド

Matlab 9.6 R2019a は 2019年03月リリース

Dockerfile準備

Dockerfile.matlab.R2019a
# Download and install Matlab Compiler Runtime v9.6 (2019a)
#
# This docker file will configure an environment into which the Matlab compiler
# runtime will be installed and in which stand-alone matlab routines (such as
# those created with Matlab's deploytool) can be executed.
#
# See http://www.mathworks.com/products/compiler/mcr/ for more info.

FROM debian:10-slim

ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -q update && \
    apt-get install -q -y --no-install-recommends \
    xorg \
      unzip \
      wget && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# Install the MCR dependencies and some things we'll need and download the MCR
# from Mathworks -silently install it
RUN mkdir /mcr-install && \
    mkdir /opt/mcr && \
    cd /mcr-install && \
    wget -q http://ssd.mathworks.com/supportfiles/downloads/R2019a/Release/5/deployment_files/installer/complete/glnxa64/MATLAB_Runtime_R2019a_Update_5_glnxa64.zip && \
    unzip -q MATLAB_Runtime_R2019a_Update_5_glnxa64.zip && \
    rm -f MATLAB_Runtime_R2019a_Update_5_glnxa64.zip && \
    ./install -destinationFolder /opt/mcr -agreeToLicense yes -mode silent && \
    cd / && \
    rm -rf mcr-install

# Configure environment variables for MCR
ENV LD_LIBRARY_PATH /opt/mcr/v96/runtime/glnxa64:/opt/mcr/v96/bin/glnxa64:/opt/mcr/v96/sys/os/glnxa64:/opt/mcr/v96/sys/opengl/lib/glnxa64
ENV XAPPLRESDIR /opt/mcr/v96/X11/app-defaults

Matlab runtimeパス /opt/mcr/v96

Dockerfileイメージビルド

# タグ指定でイメージビルド
docker build -t matlab-r2019a:latest -f Dockerfile.matlab.R2019a .



ご覧して頂き、どうも有難う御座います!
DevSamurai Ben

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

Dockerのコンテナ内でmigrateを実行すると「 failed: Name or service not known」と言われる件に関して

DockerでLaravelの環境構築をしてコンテナないで、php artisan migrateを実行すると下記のエラーが発生したので、解決策を忘備録として残しておきます。

エラー内容

root@a65fb3be52e4:/var/www# php artisan migrate

   Illuminate\Database\QueryException  : SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known (SQL: select * from information_schema.tables where table_schema = todos_app and table_name = migrations and table_type = 'BASE TABLE')

  at /var/www/vendor/laravel/framework/src/Illuminate/Database/Connection.php:669
    665| // If an exception occurs when attempting to run a query, we'll format the error
    666| // message to include the bindings with SQL, which will make this exception a
    667| // lot more helpful to the developer instead of just the database's errors.
    668| catch (Exception $e) {
  > 669|  throw new QueryException(
    670|  $query, $this->prepareBindings($bindings), $e
    671|  );
    672| }

  Exception trace:

  1   PDOException::("PDO::__construct(): php_network_getaddresses: getaddrinfo failed: Name or service not known")
      /var/www/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70

  2   PDO::__construct("mysql:host=mysql;port=3306;dbname=todos_app", "root", "", [])
      /var/www/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70

  Please use the argument -v to see more details.

failed: Name or service not known と言われているので設定ファイル内が怪しいということで確認してみることに。

各種設定ファイル

.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=todos_app
DB_USERNAME=root
DB_PASSWORD=root
docker-composer.yml
  db:
    image: mysql:5.7
    container_name: db-host_2
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: todos_app
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      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

.envファイル内で設定しているDB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD はdocker-compose.ymlで設定しているものと同じなので問題はなさそう。。

と思っていたのですが、こちらの記事によると、DB_HOSTはIPアドレスではなくて、service名を指定するとのことでした。

そのため.envファイルを下記に修正したら、無事にmigrateが実行されました。

.env
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=todos_app
DB_USERNAME=root
DB_PASSWORD=root
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerのコンテナ内でmigrateを実行した際の「 failed: Name or service not known」に関して

DockerでLaravelの環境構築をしてコンテナないで、php artisan migrateを実行すると下記のエラーが発生したので、解決策を忘備録として残しておきます。

エラー内容

root@a65fb3be52e4:/var/www# php artisan migrate

   Illuminate\Database\QueryException  : SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known (SQL: select * from information_schema.tables where table_schema = todos_app and table_name = migrations and table_type = 'BASE TABLE')

  at /var/www/vendor/laravel/framework/src/Illuminate/Database/Connection.php:669
    665| // If an exception occurs when attempting to run a query, we'll format the error
    666| // message to include the bindings with SQL, which will make this exception a
    667| // lot more helpful to the developer instead of just the database's errors.
    668| catch (Exception $e) {
  > 669|  throw new QueryException(
    670|  $query, $this->prepareBindings($bindings), $e
    671|  );
    672| }

  Exception trace:

  1   PDOException::("PDO::__construct(): php_network_getaddresses: getaddrinfo failed: Name or service not known")
      /var/www/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70

  2   PDO::__construct("mysql:host=mysql;port=3306;dbname=todos_app", "root", "", [])
      /var/www/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70

  Please use the argument -v to see more details.

failed: Name or service not known と言われているので設定ファイル内が怪しいということで確認してみることに。

各種設定ファイル

.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=todos_app
DB_USERNAME=root
DB_PASSWORD=root
docker-composer.yml
  db:
    image: mysql:5.7
    container_name: db-host_2
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: todos_app
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      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

.envファイル内で設定しているDB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD はdocker-compose.ymlで設定しているものと同じなので問題はなさそう。。

と思っていたのですが、こちらの記事によると、DB_HOSTはIPアドレスではなくて、service名を指定するとのことでした。

そのため.envファイルを下記に修正したら、無事にmigrateが実行されました。

.env
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=todos_app
DB_USERNAME=root
DB_PASSWORD=root
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む