20200110のdockerに関する記事は14件です。

Flask+MySQLで作るAPIをDocker化するまで

これは?

APIを作リたい。Flask+MySQLで作りたい。そしてDocker化したい。
この手順をメモとして残す。個人的にDocker化するところが良く分かっていないので、ここを集中的に。

やること

  1. Flask単体で簡単なAPIを作る。
  2. 1をDocker化する。
  3. MySQLを用意する。
  4. FlaskとMySQLの連携をdocker-composeで実行できるようにする。

1. Flask単体で簡単なAPIを作る。

まずなんでもいいから単純なAPIを作る。今回は、会員リスト(仮)から条件にあうデータだけをリストにして返すものを作ることに決めた。

下のファイルから、prefectureがリクエストのパラメータと一致するmail_addressのリストを返却する機能を作る。

personal_info.csv
mail_address,sex,age,name,prefecture
hoge1@gmail.com,male,18,itirou,tokyo
hoge2@gmail.com,male,23,zirou,osaka
hoge3@gmail.com,male,31,saburou,tokyo
hoge4@gmail.com,female,29,itiko,tokyo
hoge5@gmail.com,mail,11,shirou,osaka
hoge6@gmail.com,female,42,fumiko,tokyo

Flaskを使ったコードはこちら

超簡単で、app.pyを実行して、http://127.0.0.1:5000/に?pref=xxxをつけると、pref=xxxに一致するmail_addressがリストで返却される。

スクリーンショット 2020-01-02 20.43.38.png スクリーンショット 2020-01-02 20.43.26.png スクリーンショット 2020-01-02 20.43.51.png

次は、このAPIをDocker化する。

2. 1をDocker化する。

「Docker化する」とは、Dockerfileを作ってdocker buildしてDocker imageを作り、docker runでコンテナ内でapp.pyを実行してAPIリクエストが投げられる状態を作ることを目指す。

Dockerfileとは、作りたいコンテナに対し、"ベースとなるイメージを指定し、作成するコンテナの設定を記述して、コンテナ内でコマンドを実行する"動作を記述するもの。

2-1 ベースとなるイメージを指定

pythonでflaskを実行できれば良いので、pythonのイメージをベースにする。

2-2 コンテナの設定を記述

flaskのコードを動かすためには、以下が必要。

  • ローカルのソースコードやデータをコンテナに配置する。
  • 必要なライブラリをinstallする。

2-3 コンテナ内でコマンドを実行する。

作成したapp.pyを実行する。

これら2-1~2-3を意識して作ったDockerfileが以下。

# 2-1 ベースとなるイメージを指定
FROM python:3.6  
# 2-2 コンテナの設定を記述
ARG work_dir=/work  # Dockerfile内で扱う変数の作成 
ADD pure_flask $work_dir/pure_flask  # コードを/work/にコピー(ディレクトリをコピーする時は、右側にディレクトリ名を記述しないといけないので注意)

WORKDIR $work_dir/pure_flask  #  cd work_directoryのイメージ

RUN pip install -r requirements.txt  # requirements.txtで必要なライブラリをインストール
# 2-3 コンテナ内でコマンドを実行
CMD ["python", "/work/pure_flask/app.py"]   # CMDは基本的にDockerfile内に1つだけ。

requirements.txtは超簡単にflaskだけ記述。

requirements.txt
flask

この状態のDockerfileがあるディレクトリでdocker build -t flask:ver1 .を実行する。
上記コマンドの.はカレントディレクトリにあるDockerfileを使ってイメージをbuildすることを指す。

次に、docker run -it -d -p 5000:5000 flask:ver1を実行。
-dはバックグラウンド実行を、-p 5000:5000はローカルの5000番ポートと、コンテナの5000番ポートのポートフォワーディングを指定することを指してます。

この状態でローカルマシンでlocalhost:5000でブラウザで確認すると、APIのreturnが確認できる。

スクリーンショット 2020-01-03 11.01.41.png

ちなみにこの状態でdocker psdocker imagesは以下のようになる。
もしdocker psで何も表示されない場合はエラーでこけてる可能性があるため、docker ps -aで表示したコンテナIDを使って、docker logs [コンテナID]をしてあげると理由がわかるかも。

$ docker ps
> CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
> dc371c597cef        flask:ver1          "python /work/pure_f…"   9 minutes ago       Up 9 minutes        0.0.0.0:5000->5000/tcp   quizzical_margulis
$ docker images
> REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
> flask               ver1                b4cda0e56563        9 minutes ago       923MB
> python              3.6                 138869855e44        5 days ago          913MB

無事、1. Flask単体で簡単なAPIを作ると同じ動作がDocker上でも確認できた。

次は、MySQLを使うための準備をする。

3. MySQLを用意する。

MySQLもDockerで用意する。今回は、Docker-compose.yamlの利用も同時にする。

Docker-compose.yamlは、Dockerfileと似ているが、複数のコンテナの連携などを記述するためにある。
DBは接続されることが前提のため、Docker-composeで記述するのが自然だと思う。

3-1 ベースとなるイメージを指定

MySQLが使いたいため、MySQLのイメージをベースにする。

3-2 コンテナの設定を記述

MySQLの設定ファイルやデータベースの初期化をする。

3-3 コンテナ内でコマンドを実行する。

MySQLのプロセスを起動する。

Dockerfileは以下。

# 3-1 ベースとなるイメージの指定
FROM mysql:5.7

# 3-2 コンテナの設定を記述
COPY conf.d/mysql.cnf /etc/mysql/conf.d/mysql.cnf  # 文字コードの設定のセット
COPY initdb.d/init.sql /docker-entrypoint-initdb.d/init.sql  # 初期化用のSQLファイルのセット

Dockerfileの中でcopyしているconfigファイルとinit.sqlはそれぞれ以下。

mysql.cnf
[mysqld]
character-set-server=utf8

[mysql]
default-character-set=utf8

[client]
default-character-set=utf8
init.sql
CREATE TABLE `personal_info` (
    mail_address VARCHAR(100) NOT NULL,
    sex VARCHAR(6) NOT NULL,
    age INT NOT NULL,
    name VARCHAR(50) NOT NULL,
    prefecture VARCHAR(50) NOT NULL,
    createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updatedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (mail_address)
);

INSERT INTO `personal_info` (mail_address, sex, age, name, prefecture, createdAt, updatedAt)
VALUES
('hoge1_1@gmail.com', 'male',   18, 'ichirou1' , 'tokyo', current_timestamp(), current_timestamp()),
('hoge2@gmail.com', 'male',   23, 'zirou2', 'osaka', current_timestamp(), current_timestamp()),
('hoge3_3@gmail.com', 'male',   31, 'saburou', 'tokyo', current_timestamp(), current_timestamp()),
('hoge4@gmail.com', 'female', 29, 'itiko', 'tokyo', current_timestamp(), current_timestamp()),
('hoge5_5@gmail.com', 'mail',   11, 'shirou', 'osaka', current_timestamp(), current_timestamp()),
('hoge6@gmail.com', 'female', 42, 'fumiko', 'tokyo', current_timestamp(), current_timestamp());

docker-compose.yamlは以下。

version: '3'  # docker-compose.yamlの記述のバージョン
services:  
  db:  
    build: mysql  # mysqlディレクトリ配下のDockerfileを指定
    container_name: db_server  # Dockerコンテナの名前
    ports:
      - '3306:3306'  # ポートフォワーディング指定
    environment:  # 環境変数の設定
      MYSQL_ROOT_PASSWORD: pass  # MySQLのrootユーザーのパスワード
      MYSQL_DATABASE: testdb     # MySQLのスキーマ
      TZ: Asia/Tokyo             # タイムゾーンの指定
    volumes:  # MySQLのデータの永続化をするためのボリュームマウント
      - db-data/:/var/lib/mysql
    # 3-3 コンテナ内でコマンドを実行する
    command: mysqld  # mysqldコマンドの実行
volumes:
  db-data:

上記ができたら、docker-compose up -dでdbコンテナを起動する。
その後、docker exec -it [コンテナID] /bin/bashでログインし、mysql -u root -pからパスワードを入力してテーブルを確認し、init.sqlの内容が入っていればOK。

[備考]mysql周りのtips

MySQLのデータを永続化させるためのvolumeにデータが保存されない場合、Dockerホストでdocker volume lsでvolumeを確認して削除してからdocker-compose up -dすると良さげ。

init.sqlは/docker-entrypoint-initdb.d/に固定でコピーする。

次は、flaskとMySQLを接続させる。

4. FlaskとMySQLの連携をdocker-composeで実行できるようにする。

2と4で作成した二つのDockerコンテナを結合させる。
結合させるために必要なことは、以下。

  • flaskもdocker-compose.yamlに入れる。
  • flaskからMySQLへの接続が可能なようにする(ネットワークを)。
  • flaskからMySQLへの接続が可能なようにする(コードを)。

4-1 flaskもdocker-compose.yamlに入れる

flaskのコンテナをMySQLのdocker-compose.yamlに追記したものは以下。

version: '3'
services:
  api:
    build: python
    container_name: api_server
    ports:
      - "5000:5000"
    tty: yes
    environment:
      TZ: Asia/Tokyo
      FLASK_APP: app.py
    depends_on:  # apiサーバーはdbサーバーが立ってから起動
      - db
    networks:  # apiとdbを接続するための共通ネットワーク指定
      - app_net
  db:
    build: mysql
    container_name: db_server
    ports:
      - '3306:3306'
    environment:
      MYSQL_ROOT_PASSWORD: pass
      MYSQL_DATABASE: testdb
      TZ: Asia/Tokyo
    volumes:
      - ./db-data:/var/lib/mysql
    command: mysqld
    networks:
      - app_net
volumes:
  db-data:
networks:
  app_net:
    driver: bridge

services直下の階層に、dbと同じ階層としてapiを記述。

4-2 flaskからMySQLへの接続が可能なようにする(ネットワークを)。

コンテナを二つ起動し、その間で接続をする場合、二つのコンテナを同一のネットワークで扱う必要がある。
4-1のdocker-compose.yaml内にそれぞれのserviceの中に以下を追記する。

networks:
      - app_net

これにより、各コンテナがどのネットワークを利用するかを指定できる。二つを同じネットワークにしていることを意味する。
そして、docker-compose.yamlのトップレベルの階層に以下を記述する。

networks:
  app_net:
    driver: bridge

これは、dockerのネットワークの作成を意味していて、driverをbridge指定で作る指定。
これでapiとdbのコンテナが同一ネットワーク上となるため、apiからdbへの接続が可能となる。

4-3 - flaskからMySQLへの接続が可能なようにする(コードを)。

flask側のコードとモジュールの修正。
pythonからMySQLに接続する方法は色々ありそうだが、今回はmysqlclientを使った。

pip install mysqlclientでmysqlclientをインストールし、以下のようなコードで接続して使う。

import MySQLdb

conn = MySQLdb.connect(user='root', passwd='pass', host='db_server', db='testdb')
cur = conn.cursor()
sql = "select * from personal_info;"
cur.execute(sql)
rows = cur.fetchall()

このrowsには、タプルが返却され、レコード数の長さのタプルが取得できる。

rowsのイメージ.
(
 (1レコード目の1カラム目の値, 1レコード目の2カラム目の値, ...), 
 (2レコード目の1カラム目の値, 2レコード目の2カラム目の値, ...),
 (3レコード目の1カラム目の値, 3レコード目の2カラム目の値, ...)
)

これをpythonで受け取り、リストに格納してjsonで返却するようなイメージ。

修正後のソースはここ
ディレクトリ構成とか、Dockerfileの位置などもこれを参照してもらえれば。

あとは、pythonで扱いたいモジュールが増えたのでrequirements.txtにmysqlclientを追記する。

これで完了。
docker-compose up -dで全て起動したら、ローカルでhttp://0.0.0.0:5000/?pref=osakaなどを入れると、結果が確認できる。

以上。

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

Dockerで環境構築する際、ソースコードの変更が即時反映されない場合の対処法

記事の目的

docker-composeで環境構築する際に起こったRailsのソースコードを修正しても即時反映されない問題に対しての対処法を共有すること。

対処法

1.development.rbを編集

開発環境用の設定ファイルである config/environments/development.rb を編集。
「 ~ 」は元々の記述を省略しているものとする。
この中にconfig.reload_classes_only_on_change = falseという記述を追加する。

development.rb
Rails.application.configure do

~
config.reload_classes_only_on_change = false

end

2.railsコンテナを再起動

設定を記載しただけでは反映されないので、最後にRailsを再起動する。

ターミナル上で、

$ docker-compose restart 

と入力する。

以上でソースコードの変更が即時反映される。

終わりに

Dockerで環境構築をした際に、もう設定しておくと良い。

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

GitLabをDocker+Apacheでサブディレクトリ運用する

はじめに

OSSのGitリポジトリマネージャGitLabをDockerのコンテナ上で運用します
サブディレクトリで運用し,https://example.com/gitlab みたいなURLからアクセスできるようにします

構成

  • Apacheでwebブラウザからの接続を受け,リバースプロキシでlocalhost:3000にHTTP接続
    • HTTPSを使う場合でも,ApacheでHTTPS接続を終端
  • Dockerで3000番ポートからコンテナの80番ポートに接続

これにより,システムの環境とGitLabの環境をコンテナで分離して運用できます
また,ApacheでHTTPS接続を終端するので,GitLab側で余計な設定が不要になります

環境

  • Debian 9.11
  • Apache 2.4.25
  • Docker 1.13.1
  • docker-compose 1.16.1
  • GitLab 12.5.0

前提条件

ApacheやDocker, docker-composeのインストール及び基本的な設定は完了している事
HTTPSを使うならその設定も

手順

1.Dockerのコンテナを作成

  • 以下の内容でdocker-compose.ymlを作成し,コンテナを起動します
  • ポート番号は3000で最低限の設定を記述
  • 3000 や example.com とした箇所は必要に応じて書き換えてください
docker-compose.yml
web:
  image: 'gitlab/gitlab-ce:12.5.0-ce.0'
  restart: 'always'
  hostname: 'example.com'
  environment:
    GITLAB_OMNIBUS_CONFIG: |
      external_url 'http://example.com/gitlab'
  ports:
    - '3000:80'
  volumes:
    - '/srv/gitlab/config:/etc/gitlab'
    - '/srv/gitlab/logs:/var/log/gitlab'
    - '/srv/gitlab/data:/var/opt/gitlab'
$ sudo docker-compose up -d

2.Apacheでリバースプロキシの設定を追加

  • 以下の内容で/etc/apache2/sites-available/gitlab.confを作成し,設定を有効にします
/etc/apache2/sites-available/gitlab.conf
<Location /gitlab>
ProxyPass http://127.0.0.1:3000/gitlab/ nocanon
ProxyPassReverse http://127.0.0.1:3000/gitlab/
Header edit Location ^http:// https://
</Location>
$ sudo a2ensite gitlab.conf
& sudo systemctl reload apache2

動作確認

  • 以上の設定で https://example.com/gitlab からGitLabにアクセスできるはずです
    • コンテナの再起動直後はProxy Errorや502が表示されますが,数分でアクセスできるようになります

その他

  • GitLabの設定ファイルは/srv/gitlab/config/gitlab.rbから編集可能
  • 変更後は以下のコマンドでコンテナに入り,GitLabを再構成します
$ sudo docker exec -it kaizawa_web_1 bash
# gitlab-ctl reconfigure

参考

GitLab Docker images | GitLab
ApacheやNginxでHTTPS通信をリバースプロキシする - grep Tips *

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

AWS CodePipelineでgoアプリのDockerイメージをECRに格納する

実現したいこと

  1. CodeCommitのリポジトリ(hoge-repo)のmasterブランチの更新をトリガーに
    masterブランチのリソースからDockerイメージを作成しECRの対象リポジトリに格納したい
  2. hoge-repoはgolangのアプリを持っているので,イメージ作成時にアプリのビルドも行う

環境

  • Golang 1.13.5
  • Docker 18
  • AWS 東京リージョン

やったこと

CodeBuild構築

  • プロジェクト名は任意の名前

  • 送信元

    送信元はCodeCommitの対象リポジトリを選択

スクリーンショット 2020-01-10 15.53.22.png

今回はmasterマージをトリガーにするのでリファレンスタイプはブランチ
対象ブランチはmasterを指定

  • 環境

    Build環境は特に制限がなかったのでaws/codebuild/amazonlinux2-x86_64-standard:2.0
    を選択

    残りの環境設定はデフォルト

  • Buildspec
    Buildspecファイルを使用するを選択
    buildspec.yamlは後ほど

  • アーティファクト
    今回はDockerイメージのpushまでで,実際にEKSでコンテナの立ち上げまで行わないので
    アーティファクトはなしを選択

  • ログ
    ログの監視も今回は行わない

CodeBuildの権限追加

今回はCodeCommitからソースをダウンロードし,ECRにイメージプッシュするため
CodeBuildのサービスロールに以下ポリシーを付与
AWSCodeCommitReadOnlyAccess
AmazonEC2ContainerRegistryFullAccess

buildspec.yml作成

codebuildでデフォルト設定にしたので hoge-repoのルートディレクトリにbuildspec.ymlを配置

hoge-repo
|
|-- buildspec.yml
|-- Makefile
|-- Dockerfile
|-- main.go
...

buildspec.yaml

version: 0.2

phases:
  install:
    runtime-versions:
      docker: 18
    commands:
    # ECRにイメージプッシュするためにログインする
    - $(aws ecr get-login --no-include-email --region ap-northeast-1)

  pre_build:
    commands:
    # go test -v -cover ./...
    - make test

  build:
    commands:
    # go build -v .
    - make build

  post_build:
    commands:
    # docker tag \code-commit-repo-name\:latest \erc-repo-name\:latest
    # docker push \erc-repo-name\:latest
    - make push-image

CodePipeline構築

CodePipelineの新規作成

  • パイプラインの設定
    パイプライン名は任意の値を入力し,残りはデフォルト

  • ソースステージ
    ソースプロバイダにAWS CodeCommitのhoge-repo masterブランチを選択
    検索はAmazon CloudWatch Eventsを選択

  • ビルドステージ
    AWS CodeBuildの先ほど作成したプロジェクトを選択
    今回環境変数は使用しないので残りはそのまま

  • デプロイステージ
    実際にコンテナを立ち上げないのでデプロイステージはスキップする

完成

ここまでの設定でCodeCommitのmasterブランチの更新をトリガーに
GoアプリがビルドされたDockerイメージを作成し,ECRにプッシュする構成ができた.

この後

Pipeline実行する毎に goモジュール(外部ライブラリ)をダウンロードするのはイケてない(5分ぐらいかかる)
一度ダウンロードしたモジュールはキャッシュしておきたい(この後盛大にハマる)

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

Universal Base Images (UBI) 8 を日本語ロケールにする

配布されている Universal Base Images (UBI) 8 のロケールは C.utf8 ですが、用途によっては日本語ロケール ja_JP.utf8 で使用したいことがあります。そこで、UBI 8 を日本語ロケールにする方法を調べてみました。
ここで扱うのは、UBI 8 で UBI minimal ではありません。

まずは、調査してみる

docker run --rm -it registry.access.redhat.com/ubi8/ubi:latest bash で起動して、淡い期待をもって locale -a を実行してみましたが、やはり最初から日本語ロケールが組み込まれているということはありませんでした。

C:\>docker run --rm -it registry.access.redhat.com/ubi8/ubi:latest bash
[root@61670851e75a /]# locale -a
C
C.utf8
POSIX

次に、利用できる langpacks をサーチしてみましたが、提供されているのは英語のものだけです。
glibc-all-langpacks.x86_64 がありますが、これを インストールしてもロケールは追加されませんでした。

[root@61670851e75a /]# dnf search langpacks
Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Last metadata expiration check: 0:02:02 ago on Fri Jan 10 07:24:31 2020.
========================================================= Name & Summary Matched: langpacks ==========================================================
langpacks-en.noarch : English langpacks meta-package
langpacks-en.noarch : English langpacks meta-package
============================================================== Name Matched: langpacks ===============================================================
glibc-all-langpacks.x86_64 : All language packs for glibc.

locale でサーチすると、いくつかパッケージが見つかりました。
glibc-common.x86_64 をインストールすると、en_XX 系のロケールはインストールできましたが、日本語は追加されません。
残るは、glibc-locale-source.x86_64 なるパッケージです。source とあるので、これを使って日本語ロケールを定義することにします。

[root@61670851e75a /]# dnf search locale
Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Last metadata expiration check: 0:17:23 ago on 2020年01月10日 07時24分31秒.
=========================================================== Name & Summary Matched: locale ===========================================================
glibc-locale-source.x86_64 : The sources for the locales
perl-Encode-Locale.noarch : Determine the locale encoding
perl-Locale-Codes.noarch : Distribution of modules to handle locale codes
perl-Locale-Maketext-Simple.noarch : Simple interface to Locale::Maketext::Lexicon
================================================================ Name Matched: locale ================================================================
perl-Locale-Maketext.noarch : Framework for localization
============================================================== Summary Matched: locale ===============================================================
glibc-langpack-en.x86_64 : Locale data for en
glibc-common.x86_64 : Common binaries and locale data for glibc
glibc-common.x86_64 : Common binaries and locale data for glibc

日本語ロケールを組み込む

dnf install -y glibc-locale-source で source をインストールし、localedef で日本語ロケールを定義することで、日本語ロケールが使用できるようになりました。
手順は以下の通りですが、分かってしまうと簡単ですね。

C:\>docker run --rm -it registry.access.redhat.com/ubi8/ubi:latest bash
[root@0f88101d5c72 /]# dnf install -y glibc-locale-source
(出力は省略)
[root@0f88101d5c72 /]# localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
[root@0f88101d5c72 /]# locale -a
C
C.utf8
POSIX
ja_JP.utf8
[root@0f88101d5c72 /]# echo LANG=ja_JP.UTF-8 > /etc/locale.conf
[root@0f88101d5c72 /]# export LANG=ja_JP.UTF-8
[root@0f88101d5c72 /]# date
2020年  1月 10日 金曜日 07:53:26 UTC

タイムゾーンを変更する

date コマンドの出力を見て、タイムゾーンの変更が必要なことを思い出しました。
まずは、調査ですが、zoneinfo を確認してみると、各地域のゾーン情報(tzdata)が入っていて、Asia/Tokyo もありました。

[root@0f88101d5c72 /]# ls /usr/share/zoneinfo/
Africa      Atlantic   Canada  EST5EDT  GB       GMT0       Indian   Kwajalein  Mexico   PST8PDT   ROK        UTC        iso3166.tab  tzdata.zi
America     Australia  Chile   Egypt    GB-Eire  Greenwich  Iran     Libya      NZ       Pacific   Singapore  Universal  leapseconds  zone.tab
Antarctica  Brazil     Cuba    Eire     GMT      HST        Israel   MET        NZ-CHAT  Poland    Turkey     W-SU       posix        zone1970.tab
Arctic      CET        EET     Etc      GMT+0    Hongkong   Jamaica  MST        Navajo   Portugal  UCT        WET        posixrules
Asia        CST6CDT    EST     Europe   GMT-0    Iceland    Japan    MST7MDT    PRC      ROC       US         Zulu       right
[root@0f88101d5c72 /]# ls /usr/share/zoneinfo/Asia/Tokyo
/usr/share/zoneinfo/Asia/Tokyo

タイムゾーンは、普通の方法で変更するだけで済みました。

[root@0f88101d5c72 /]# ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
[root@0f88101d5c72 /]# export TZ=Asia/Tokyo
[root@0f88101d5c72 /]# date
2020年  1月 10日 金曜日 17:03:05 JST

日本語ロケールにしたイメージをビルドする

手順が分かったので、Dockerfile を作ってイメージをビルドします。以下のような Dockerfile にしてみました。

FROM registry.access.redhat.com/ubi8/ubi:latest
RUN  dnf update -y \
  && dnf install -y glibc-locale-source \
  && localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8 \
  && echo LANG=ja_JP.UTF-8 > /etc/locale.conf \
  && dnf remove -y glibc-locale-source \
  && dnf clean all \
  && ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
ENV LANG="ja_JP.UTF-8" \
    TZ="Asia/Tokyo"

ビルドして確認してみます。

C:\ubi-jp>docker build -t ubi8-jp .
Sending build context to Docker daemon  2.048kB
(省略)
Successfully tagged ubi8-jp:latest
(省略)

C:\ubi-jp>docker run --rm -it ubi8-jp bash
[root@143587d7dbf8 /]# date
2020年  1月 10日 金曜日 17:09:51 JST
[root@143587d7dbf8 /]# ls -al
total 60
drwxr-xr-x   1 root root 4096  1月 10 17:09 .
(省略)
drwxr-xr-x   1 root root 4096 12月 11 02:50 var
[root@143587d7dbf8 /]# sss
bash: sss: command not found
[root@143587d7dbf8 /]#

最後に

UBI 8 を日本語ロケールに変更することができました。
詳細は触れませんが、UBI-minimal 8 や UBI 7 でもチャレンジしてみました。

UBI-minimal 8 は、UBI 8 と同じ方法で日本語ロケールを追加できました。但し、localedef が使用する gzip が入っていないので、追加する必要があります。
さらに、ゾーン情報(tzdata)は自力で追加する必要がありました。microdnf install -y tzdata で追加したいところですが、インストール後に不要なものを rm コマンドで削除しているようで、microdnf install -y tzdata を実行しても追加できませんでした。
rpm パッケージをダウンロードして rpm2cpio と cpio -idv を使って力ずくで追加するしか方法がなさそうでした。

microdnf install -y cpio
curl https://cdn-ubi.redhat.com/content/public/ubi/dist/ubi8/8/x86_64/baseos/os/Packages/t/tzdata-2019c-1.el8.noarch.rpm | rpm2cpio | cpio -idv
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
microdnf remove -y cpio
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nexus RepositoryのOrientDBを復旧させた話

概要

  • Nexus Repositoryで500エラーが返ってくるようになり、OrientDbを再作成して復旧させた

環境

発端

  • Nexusへのファイルアップロードが突然できなくなった。
    • 起動はしているのに、アップロードができない。
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.339 s
[INFO] Finished at: 2020-01-06T01:30:50Z
[INFO] Final Memory: 10M/239M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy-file (default-cli) on project standalone-pom: Failed to deploy artifacts: Could not transfer artifact jp.hoge.fuga:api:jar:1.0.1-20200106.013045-1 from/to remote-repository (https://example.com/nexus/repository/maven-api-snapshots/): Failed to transfer file: https://example.com/nexus/repository/maven-api-snapshots/jp/hoge/fuga/api/1.0.1-SNAPSHOT/api-2.10.1-20200106.013045-1.jar. Return code is: 500, ReasonPhrase: Server Error. -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
  • ログを見ると、中で使っているDB(OrientDB)でエラーとなっている
2020-01-06 01:30:44,913+0000 WARN  [qtp637974386-634] admin org.sonatype.nexus.repository.httpbridge.internal.ViewServlet - Failure servicing: PUT /nexus/repository/maven-api-snapshots/jp/hoge/fuga/api/1.0.1-SNAPSHOT/api-2.10.1-20200106.013045-1.jar
com.orientechnologies.orient.core.exception.OStorageException: Error during transaction commit
    DB name="component"
2020-01-06 01:30:44,913+0000 ERROR [qtp637974386-621] admin com.orientechnologies.orient.core.storage.impl.local.paginated.OLocalPaginatedStorage - $ANSI{green {db=component}} Exception `6C3A2748` in storage `component`
java.lang.NullPointerException: null

やったこと

# docker-compose run --rm nexus_service sh
sh-4.2$ 
sh-4.2$ java -version
sh: java: command not found
  • 何と、当該バージョンのNexusには、javaがインストールされていなかった…
  • ということで、一旦上記記事の方と同じバージョン(3.12.0)にアップデートした上で、OrientDBの復旧手順をやってみた
# docker-compose run --rm nexus_service sh
sh-4.2$ 
sh-4.2$ java -version
java version "1.8.0_172"
Java(TM) SE Runtime Environment (build 1.8.0_172-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)
sh-4.2$ 
sh-4.2$ # ↑よかった、javaがインストールされている!!
sh-4.2$ 
sh-4.2$ whoami
nexus
sh-4.2$ 
sh-4.2$ pwd
/
sh-4.2$ cd /opt/sonatype/nexus/
sh-4.2$ 
sh-4.2$ java -jar ./lib/support/nexus-orient-console.jar
OrientDB console v.2.2.34 (build f340442755a31eabc91b87cb3ef99eda5cee6ebd, branch 2.2.x) https://www.orientdb.com
Type 'help' to display all the supported commands.

orientdb> ### 以下コマンドのみ、結果略 ###
orientdb> CONNECT 'plocal:/nexus-data/db/analytics' admin admin
orientdb> EXPORT DATABASE analytics-export
orientdb> DROP DATABASE
orientdb> CREATE DATABASE 'plocal:/nexus-data/db/analytics'
orientdb> IMPORT DATABASE analytics-export.json.gz
orientdb> DISCONNECT
orientdb> exit

sh-4.2$ exit
# # コンテナ再起動
# docker-compose down
# docker-compose up -d
  • 無事復旧できた。
    • 今回壊れていたのはcomponent DBのみだったので、他のDBの再作成は行っていない。

原因

  • いまだに不明。

失敗したこと

  • Nexus3.4.0でjavaがインストールされていなかったので、自力でインストールして上記手順を実施したところ、root実行してしまったため、コンテナ起動時にPermissionエラーが出続けてしまい立ち上がらなくなってしまった。

参考

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

[備忘録]dockerでjava環境を一から作る

DockerHubにあるjava環境イメージをpullしたら早いのに、一から作らないと落ち着かない損な性格なので作ってみた備忘録です。

環境

  • macOS Catalina
  • Docker Desktop for Mac (インストール済)

手順

1. ubuntuイメージ取得

$ docker pull ubuntu

2. ubuntuコンテナ起動

$ docker run -it ubuntu bash

以降はubuntuでの作業

3. apt-getコマンドの更新

$ apt-get update

4. 最低限必要なコマンドをインストール

curlコマンド

$ apt-get install curl

unzipコマンド

$ apt-get install unzip

zipコマンド

$ apt-get install zip

5. sdkmanのインストール

$ curl -s "https://get.sdkman.io" | bash
$ source "/root/.sdkman/bin/sdkman-init.sh"

確認

$ sdk help
==== BROADCAST =================================================================
* 2020-01-08: Asciidoctorj 2.2.0 released on SDKMAN! #asciidoctorj
* 2020-01-07: Gradle 6.1-rc-2 released on SDKMAN! #gradle
* 2020-01-06: Jbang 0.4.0.1 released on SDKMAN! #jbang
================================================================================

Usage: sdk <command> [candidate] [version]
       sdk offline <enable|disable>

   commands:
       install   or i    <candidate> [version] [local-path]
       uninstall or rm   <candidate> <version>
       list      or ls   [candidate]
       use       or u    <candidate> <version>
       default   or d    <candidate> [version]
       current   or c    [candidate]
       upgrade   or ug   [candidate]
       version   or v
       broadcast or b
       help      or h
       offline           [enable|disable]
       selfupdate        [force]
       update
       flush             <broadcast|archives|temp>

   candidate  :  the SDK to install: groovy, scala, grails, gradle, kotlin, etc.
                 use list command for comprehensive list of candidates
                 eg: $ sdk list
   version    :  where optional, defaults to latest stable if not provided
                 eg: $ sdk install groovy
   local-path :  optional path to an existing local installation
                 eg: $ sdk install groovy 2.4.13-local /opt/groovy-2.4.13

SDKMANのインストールは終わり

6. javaのインストール

インストールできるjavaを確認

$ sdk list java
================================================================================
Available Java Versions
================================================================================
 Vendor        | Use | Version      | Dist    | Status     | Identifier
--------------------------------------------------------------------------------
 AdoptOpenJDK  |     | 13.0.1.j9    | adpt    |            | 13.0.1.j9-adpt      
               |     | 13.0.1.hs    | adpt    |            | 13.0.1.hs-adpt      
               |     | 12.0.2.j9    | adpt    |            | 12.0.2.j9-adpt      
               |     | 12.0.2.hs    | adpt    |            | 12.0.2.hs-adpt      
               |     | 11.0.5.j9    | adpt    |            | 11.0.5.j9-adpt      
               | >>> | 11.0.5.hs    | adpt    | installed  | 11.0.5.hs-adpt      
               |     | 8.0.232.j9   | adpt    |            | 8.0.232.j9-adpt     
               |     | 8.0.232.hs   | adpt    |            | 8.0.232.hs-adpt     
 Amazon        |     | 11.0.5       | amzn    |            | 11.0.5-amzn         
               |     | 8.0.232      | amzn    |            | 8.0.232-amzn        
 Azul Zulu     |     | 13.0.1       | zulu    |            | 13.0.1-zulu         
               |     | 12.0.2       | zulu    |            | 12.0.2-zulu         
               |     | 11.0.5       | zulu    |            | 11.0.5-zulu         
               |     | 10.0.2       | zulu    |            | 10.0.2-zulu         
               |     | 9.0.7        | zulu    |            | 9.0.7-zulu          
               |     | 8.0.232      | zulu    |            | 8.0.232-zulu        
               |     | 7.0.242      | zulu    |            | 7.0.242-zulu        
               |     | 6.0.119      | zulu    |            | 6.0.119-zulu        
 Azul ZuluFX   |     | 11.0.2       | zulufx  |            | 11.0.2-zulufx       
               |     | 8.0.202      | zulufx  |            | 8.0.202-zulufx      
 BellSoft      |     | 13.0.1       | librca  |            | 13.0.1-librca       
               |     | 12.0.2       | librca  |            | 12.0.2-librca       
               |     | 11.0.5       | librca  |            | 11.0.5-librca       
               |     | 8.0.232      | librca  |            | 8.0.232-librca      
 GraalVM       |     | 19.3.0.r11   | grl     |            | 19.3.0.r11-grl      
               |     | 19.3.0.r8    | grl     |            | 19.3.0.r8-grl       
               |     | 19.3.0.2.r11 | grl     |            | 19.3.0.2.r11-grl    
               |     | 19.3.0.2.r8  | grl     |            | 19.3.0.2.r8-grl     
               |     | 19.2.1       | grl     |            | 19.2.1-grl          
               |     | 19.1.1       | grl     |            | 19.1.1-grl          
               |     | 19.0.2       | grl     |            | 19.0.2-grl          
               |     | 1.0.0        | grl     |            | 1.0.0-rc-16-grl     
 Java.net      |     | 15.ea.4      | open    |            | 15.ea.4-open        
               |     | 14.ea.30     | open    |            | 14.ea.30-open       
               |     | 13.0.1       | open    |            | 13.0.1-open         
               |     | 12.0.2       | open    |            | 12.0.2-open         
               |     | 11.0.5       | open    |            | 11.0.5-open         
               |     | 10.0.2       | open    |            | 10.0.2-open         
               |     | 9.0.4        | open    |            | 9.0.4-open          
               |     | 8.0.232      | open    |            | 8.0.232-open        
 SAP           |     | 12.0.2       | sapmchn |            | 12.0.2-sapmchn      
               |     | 11.0.4       | sapmchn |            | 11.0.4-sapmchn      
================================================================================
Use the Identifier for installation:

    $ sdk install java 11.0.3.hs-adpt
================================================================================

インストールしたいjavaを指定

$ sdk install java 8.0.232-open

確認

root@d9b652b0db21:/# java -version
openjdk version "1.8.0_232"
OpenJDK Runtime Environment (build 1.8.0_232-b09)
OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode)

以上で、DockerにJava環境を作りました。
あとは煮るなり焼くなり。

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

manjaroブート時にdocker deamonを起動する

sudo systemctl enable docker

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

Railsで開発した個人アプリにDockerを導入する手順と最低限の知識

Railsで開発した個人アプリに、後からDockerを導入しました。
その時知識不足なせいでハマってしまった場面があったので、自分の中で整理してアウトプットすることを目的にこの記事を書き残します。

ちなみに、以下の記事を主に参考にさせていただきました。
DockerをMacにインストールする
Docker + Rails + Puma + Nginx + MySQL

RailsアプリにDockerを導入する手順+事前知識

まずは事前知識として、これは知っておいたほうがいいというものを簡単に書いていきます。

事前知識 - Docker関係

Docker(ドッカー)

※1.軽量な仮想化環境を実現するためのツール。

OS やアプリケーションを設定したものを丸ごと実行イメージとして保存できるので、Docker が導入されている別のマシンにそのまま持って行くことができる。

実行環境をテキストファイルとして共有できるのでとても便利。

※1.仮想化環境とは、コンピュータ上にソフトウェアによって仮想的に構築されたコンピュータ(仮想マシン)が備える仕様や機能の総体のこと。

Dockerイメージ

Dockerイメージは、コンテナを起動させるためのベースとなるもの(オブジェクト指向でいうと「クラス」にあたる)

テキストファイル(Dockerfile)からビルドされる。(後に記述)

DockerHub(Docker向けのコンテナ共有サービス)では、既に多くのイメージが公開されている。

Dockerコンテナ

Dockerのコンテナは、 Dockerイメージを元に作成される仮想環境の実行部分(オブジェクト指向でいうと「インスタンス」にあたる)

原則1コンテナ1アプリ。

Dockerfile(ドッカーファイル)

指定したベースのDockerイメージに加える変更を記述するファイル。

Dockerfileを使うことでオリジナルのDockerイメージを作成することができる。

docker-compose(ドッカーコンポーズ)

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

docker-composeを使用する際は「docker-compose.yml」が必要になる。

事前知識 - サーバ関係

ミドルウェア

OSとアプリケーションの間に入り、中間的な処理を行うソフトウェアのこと。

ー 例 ー

  • Webサーバ
    • Apache、NginXなど
  • APサーバ
    • Puma
    • Unicornなど
  • DBサーバ
    • MySQL
    • PostgreSQLなど

Nginx(エンジンエックス)

webサーバの一つ。

Apacheよりも処理能力が高い。

puma(プーマ)

※1.Rackという機能を提供するためのアプリケーションサーバ。

webサーバの1つでもある。

※1.RackとはWeb サーバと Rubyやフレームワークをつなぐ最小のインタフェースを提供するもの。

Docker導入手順

① Docker for Macを公式サイトからインストール、そして起動

公式サイトで会員登録を済ませた後、Docker for Macをダウンロードしインストール。

インストールが終わったら、Dockerを起動しておく。
(MACの画面上部にDockerのマークが出れば起動できてる証拠)

②作成済みのアプリケーションフォルダの直下に「Dockerfile」、「docker-compose.yml」ファイルを新しく作成する。

フォルダ構成

  • 既存のRailsアプリフォルダ
    • app
    • bin
    • config
    • db
    • ・・・
    • Dockerfile
    • docker-compose.yml

③Dockerfileに記述する(アプリケーションフォルダ直下)

Dockerfile
FROM ruby:2.5.1

RUN apt-get update && \
    apt-get install -y mysql-client nodejs vim --no-install-recommends && \
    rm -rf /var/lib/apt/lists/*

RUN mkdir /myproject

WORKDIR /myproject

ADD Gemfile /myproject/Gemfile
ADD Gemfile.lock /myproject/Gemfile.lock

RUN gem install bundler
RUN bundle install

ADD . /myproject

RUN mkdir -p tmp/sockets

④docker-compose.ymlに記述する(アプリケーションフォルダ直下)

docker-compose.yml
version: '2'
services:
  db:
    image: mysql:5.6
    environment:
      - ./environments/db.env
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "4306:3306"

  app:
    build: .
    command: bundle exec puma -C config/puma.rb
    volumes:
      - .:/myproject
      - public-data:/myproject/public
      - tmp-data:/myproject/tmp
      - log-data:/myproject/log

  web:
    build:
      context: containers/nginx
    volumes:
      - public-data:/myproject/public
      - tmp-data:/myproject/tmp
    ports:
      - 80:80
volumes:
  mysql-data:
  public-data:
  tmp-data:
  log-data:

⑤アプリケーションフォルダ直下に「environments」フォルダを作成、さらにenvironmentsフォルダ直下に「db.env」ファイルを作成する。

  • 既存のRailsアプリフォルダ
    • app
    • bin
    • config
    • db
    • environments
      • db.env
    • ・・・
    • Dockerfile
    • docker-compose.yml

⑥db.envを編集

environments/db.env
MYSQL_ROOT_PASSWORD=password
MYSQL_USER=user
MYSQL_PASSWORD=password

⑦database.ymlを編集

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch('MYSQL_USER') { 'root' } %>
  password: <%= ENV.fetch('MYSQL_PASSWORD') { 'root' } %>
  host: db

⑧アプリケーションフォルダ直下に「containers」フォルダを作成、さらにcontainersフォルダ直下に「nginx」フォルダを作成する。

フォルダ構成

  • 既存のRailsアプリフォルダ
    • app
    • bin
    • config
    • containers
      • nginx
    • db
    • environments
      • db.env
    • ・・・
    • Dockerfile
    • docker-compose.yml

⑨作成したnginxフォルダ直下に「Dockerfile」、「nginx.conf」ファイルを作成する。

  • 既存のRailsアプリフォルダ
    • app
    • bin
    • config
    • containers
      • nginx
        • Dockerfile
        • nginx.conf
    • db
    • environments
      • db.env
    • ・・・
    • Dockerfile
    • docker-compose.yml

⑩Dockerfileに記述する(containers/nginxフォルダ直下)

containers/nginx/Dockerfile
FROM nginx:1.15.8

RUN rm -f /etc/nginx/conf.d/*

ADD nginx.conf /etc/nginx/conf.d/myproject.conf

CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf

⑪nginx.confに記述する(containers/nginxフォルダ直下)

containers/nginx/nginx.conf
upstream myproject {
  server unix:///myproject/tmp/sockets/puma.sock;
}

server {
  listen 80;
  server_name 13.112.60.229;

  access_log /var/log/nginx/access.log;
  error_log  /var/log/nginx/error.log;

  root /myproject/public;

  client_max_body_size 100m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;
  try_files  $uri/index.html $uri @myproject;
  keepalive_timeout 5;

  location @myproject {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://myproject;
  }
}

⑫puma.rbを編集

puma.rb
app_root = File.expand_path("../..", __FILE__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"

stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true

⑬ターミナルでコマンドを実行

ファイルの準備が整ったら、最後にターミナル上でコマンドを実行。
(railsアプリケーションフォルダ内で実行する)

イメージを構築する

ターミナル
$ docker-compose build

railsのコンテナを作成し、データベースの作成処理を行う

ターミナル
$ docker-compose run --rm app rake db:create db:migrate

全てのコンテナを構築・起動する

ターミナル
$ docker-compose up

上記の流れが終わったあとlocalhostにアクセスすると、しっかり確認することができました。

ちなみに今回書きまとめたものは、DBもDockerで管理することになりますが、DBはローカルのものを参照したいという場合、以下の記事が参考になるかと思います。
既存のRailsアプリをDocker化し、ローカルのDBに接続する方法

(おまけ)

Dockerfileに記述できるコマンド一覧

コマンド 意味
FROM ベースとなるイメージ
RUN docker build 時に実行するコマンド
CMD docker run 時に実行するコマンド
ENTRYPOINT docker run 時に実行するコマンド
MAINTAINER 作者情報
LABEL ラベル情報(メタデータ)
EXPOSE 公開ポート番号
ENV 環境変数
ARG 一時変数
COPY ホストからコンテナへのファイルコピー
ADD ファイル/ディレクトリの追加
VOLUME ボリュームのマウント
USER 実行ユーザ
SHELL シェル指定
WORKDIR ワークディレクトリ
ONBUILD ビルド時に実行するコマンド
STOPSIGNAL コンテナ終了時に送信されるシグナル
HEALTHCHECK ヘルスチェック

ターミナル上で実行できるdocker-composeコマンド一覧

コマンド 意味
build サービスの構築または再構築
config compose ファイルの確認と表示
create サービスの作成
down コンテナ・ネットワーク・イメージ・ボリュームの停止と削除
events コンテナからリアルタイムにイベントを受信
help コマンド上でヘルプを表示
kill コンテナを kill (強制停止)
logs コンテナの出力を表示
pause サービスを一時停止
port ポートに割り当てる公開用ポートを表示
ps コンテナ一覧
pull サービス用イメージの取得
restart サービスの再起動
rm 停止中のコンテナを削除
run 1度だけコマンドを実行
scale サービス用コンテナの数を指定ド
start サービスの開始
stop サービスの停止
up コンテナの作成と開始
version Docker Compose のバージョン情報を表示
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

既存のRailsアプリをDocker上で環境構築する方法+sequel proによるDBコンテナ可視化

はじめに

新規アプリをDocker環境で開発するやり方はたくさんあるけど、既存アプリをDocker環境で構築するやり方は全然見当たらず、わりと苦労しました。
振り返ってみると新規アプリでの構築の仕方とあまり変わらないはずなのですが、色々エラー出て苦労したのでまとめておきます。

個々のコマンドの意味もできるだけ記載しました。
単なる環境構築だけでなく、DBコンテナのsequel proによる可視化やAPPコンテナでのbinding.pryの仕方、bundle install後にbuildし直さなくてもよい設定にする方法などもまとめました。

同じく既存のRailsアプリをDocker上で構築したい人の参考になれば幸いです。

内容について間違っていたら教えていただけると嬉しいです。

開発環境

  • Ruby: 2.5.1
  • Rails: 5.2.4
  • MySQL: 5.6
  • MacOS

前提

  • Docker for Macはインストール済み
  • Dockerについての基礎知識
  • 今回は開発環境のみ

対象読者

作成した既存のアプリをDocker上で構築したい人

目次

  • コンテナ起動までの大まかな流れ
  • 実際の作業
  • 番外編:sequel proによるDBコンテナの可視化
  • 開発する上でのDockerコマンド
  • おまけ
    • railsコンテナ上でbinding.pryをする方法
    • railsコンテナ上でbundle installした時に、変更内容をコンテナ上に反映させる方法

コンテナ起動までの大まかな流れ

DockerfileにてRubyのベースイメージをもとにイメージを作成する

作成したイメージをもとにdocker-compose.ymlでappコンテナを作成すると同時に、DBのコンテナのイメージを作成し、これらのコンテナを連携させる

database.ymlを修正してappコンテナからdbコンテナへ接続できるように設定する

実際の作業

  1. Dockerfileとdocker-compose.ymlの作成
  2. Dockerfileの記載
  3. docker-compose.ymlの記載
  4. database.ymlの変更

1. Dockerfileとdocker-compose.ymlの作成

まず、開発しているアプリで、Dockerfileとdocker-compose.ymlを以下のように作成します。

アプリ名
  |- app
  |- bin
  |- config
      #略
  |- vendor
  - .gitignore
  - config.rb
  - Dockerfile           #追加
  - docker-compose.yml  #追加
  - Gemfile
  - Gemfile.lock
      #略

2. Dockerfileの記載

続いてDockerfileの中身を書いていきます。
myprojectのところはコンテナ起動の際に作成するディレクトリ名なので、何でも大丈夫です
ただし、それ以降の記述でも随時書き換えてください

Dockerfile
FROM ruby:2.5.1

RUN apt-get update && \
    apt-get install -y mysql-client nodejs vim --no-install-recommends && \
    rm -rf /var/lib/apt/lists/*

RUN mkdir /myproject

WORKDIR /myproject

ADD Gemfile /myproject/Gemfile
ADD Gemfile.lock /myproject/Gemfile.lock

RUN gem install bundler
RUN bundle install

ADD . /myproject

詳細な説明は省きますが、ざっと説明すると

  • ruby2.5.1をベースイメージとする
  • コンテナ内で必要なコマンドをインストール
  • myprojectというディレクトリを作成して基点にする
  • Gemfileをコンテナ上にコピーした後、bundle install
  • ローカルのディレクトリ、ファイルをコンテナ上にコピー

という感じかと思います。

3. docker-compose.ymlの記載

Rubyのコンテナは作成できるようになりました。
続いてこれをもとにアプリケーションのコンテナとデータベースのコンテナを作成し、それらのコンテナをリンクさせるための作業をしていきます。
docker-compose.ymlを以下のように記載します。
*mysqlは8.0以上だと認証方法が異なるようなので注意
https://qiita.com/yensaki/items/9e453b7320ca2d0461c7

docker-compose.yml
version: '2'
services:
  db:
    image: mysql:5.6
    volumes:
      - mysql-data:/var/lib/mysql  #データの永続化のために必要
    ports:
      - "4306:3306" #両方3306でもok。詳細は下の「番外編:DBをsequel proで可視化したい」へ

  app:
    tty: true       #コンテナ上でbinding.pryするために必要
    stdin_open: true  #コンテナ上でbinding.pryするために必要
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myproject  #ローカルのディレクトリをコンテナ上にマウント
      - bundle:/usr/local/bundle  #bundle installした後buildし直さなくてよくなる
    links:
      - db

volumes:
  mysql-data:
  bundle:   #bundle installした後buildし直さなくてよくなる

要点は以下

  • versionは2でも3でもいいと思いますが、使えるコマンドが違ってくるみたいです。
  • servicesのところにdbとappがありますが、これらがそれぞれコンテナになります。
  • appのコンテナのlinksにdbがあり、これによってappコンテナとdbコンテナが連携できるようになります
  • 一番下のvolumesには永続化させたいデータを記載
  • appコンテナ上でvolumes: - .:/myprojectとすることで、ローカルのディレクトリをマウントしている。
  • dbコンテナ上でvolumes: -mysql-data:/var/lib/mysqlとすることでデータベースで変更されたデータを永続化。この記述がないと、コンテナを壊した時に変更したデータが消えてしまいます。
  • bundle installとbinding.pryのための記述は本記事、最後のおまけを参照

4. database.ymlの変更

これまでの作業でappコンテナとdbコンテナを連携させる設定をしました。
最後にappコンテナからdbコンテナに接続するために、接続設定をします。
database.ymlの中身はおそらく初期設定のままだとこんな感じの記述になってるかと思います。

config/database.yml変更前
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

このままだとsocket通信でDB接続をするので、せっかく作成したdbコンテナが意味なくなってしまいます。
作成したdbコンテナに接続するために以下のように変更します。

config/database.yml変更後
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:password
  host: db   #変更(docker-compose.ymlのservice名を記載)

usernameやpasswordは環境変数で設定している記事もいくつか見ますが、開発環境なら気にしなくてもいいかなと思いました。
本番環境ではちゃんと環境変数を設定します。

以上で準備ができました。
あとはターミナルで該当アプリのディレクトリまで移動して、docker-compose upと入力するだけです
(Gemfile.lockの中身を削除して空にしないとエラーになるかもしれません)
localhost:3000で接続確認して終了です!

今回はMySQLを使いましたが、他のDBでも可能なはずです(未検証)
*ポート番号は変わるはずなのでご注意ください

番外編:DBをsequel proで可視化したい

今まで開発していた時、DBをsequel proで可視化していて便利だったのですが、docker上のDBも可視化したい!
という方に向けて以下に方法を記載します

docker-compose.ymlで以下のように記載していました
Ruby:docker-compose.yml
db:
ports:
- "4306:3306"

これはホストが4306で接続した時にコンテナ上では3306に置き換えますという意味です。
準備はこれでokなのでsequel proで接続します。
sequel proを開いて、標準タブに切り替えます。
そこで以下の内容を入力します

名前: 任意、変えなくてもok
ホスト: 127.0.0.1
ユーザー名: root (database.ymlに記載のユーザー名)
パスワード: password (database.ymlにパスワード)
データベース: 空でok
ポート: 4306docker-compose.ymlportsに記載した左側)

ホストの127.0.0.1は自分自身を表すIPアドレス

これで見れるようになるはず!

その他開発する上で必要なコマンド

docker上でrails g controllerやrails db:migrateなどを行う時は以下のようにコンテナを通して入力します
appの部分はdocker-compose.ymlで作成したコンテナ名のappのことです

docker-compose run --rm app 入力したいコマンド(例: rails db:migrate)

その他必要なコマンドは以下の記事参照
https://qiita.com/gold-kou/items/44860fbda1a34a001fc1



全てのコンテナやイメージを削除する場合はこちら

#全てのコンテナ停止
docker stop $(docker ps -q)

#全てのコンテナ削除
docker rm $(docker ps -q -a)

#全てのイメージ削除
docker rmi $(docker images -q)

おまけ

bundle installしたい時

開発していく中で、gemを追加してbundle installしたい場面が出てくると思います
そのままやってもできるんですが、追加したgem内容がコンテナ内に反映されないため、イメージをbuildし直さなくてはなりません。
いくつか解決方法はあるみたいですが、今回はvolumeでマウントするという方法で解決しました。

docker-compose.yml
app:
  volumes:
    - bundle:/usr/local/bundle
  
 #中略

volumes:
  bundle:

参考記事
https://qiita.com/neko-neko/items/abe912eba9c113fd527e

bindin.pryしたい時

binding.pryをするためには以下の記述を追加します

docker-compose.yml
app:
  tty: true
  stdin_open: true

おわりに

dockerについて全くわからないところから環境構築するのはかなり大変でした
自分なりにまとめられて良かった
同じような状況の人の参考になれば幸いです

間違ってる場所があれば指摘していただけると幸いです

本番環境でDockerを使うのも苦労したので、そのうち開発環境との違いなどもまとめようかなと思います

参考記事

Dockerについての概要と色々なTIPSを知りたい場合は下記リンクがおすすめ
https://qiita.com/gold-kou/items/44860fbda1a34a001fc1

実際の作業で参考にした記事
https://qiita.com/azul915/items/5b7063cbc80192343fc0
https://qiita.com/Nishi53454367/items/aee4cf0c346bc115be99

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

既存のRailsアプリをDockerコンテナで動かす方法+sequel proによるDBコンテナ可視化

はじめに

新規アプリをDocker環境で開発するやり方はたくさんあるけど、既存アプリをDocker環境で構築するやり方は全然見当たらず、わりと苦労しました。
振り返ってみると新規アプリでの構築の仕方とあまり変わらないはずなのですが、色々エラー出て苦労したのでまとめておきます。

個々のコマンドの意味もできるだけ記載しました。
単なる環境構築だけでなく、DBコンテナのsequel proによる可視化やAPPコンテナでのbinding.pryの仕方、bundle install後にbuildし直さなくてもよい設定にする方法などもまとめました。

同じく既存のRailsアプリをDocker上で構築したい人の参考になれば幸いです。

内容について間違っていたら教えていただけると嬉しいです。

開発環境

  • Ruby: 2.5.1
  • Rails: 5.2.4
  • MySQL: 5.6
  • MacOS

前提

  • Docker for Macはインストール済み
  • Dockerについての基礎知識
  • 今回は開発環境のみ

対象読者

作成した既存のアプリをDocker上で構築したい人

目次

  • コンテナ起動までの大まかな流れ
  • 実際の作業
  • 番外編:sequel proによるDBコンテナの可視化
  • 開発する上でのDockerコマンド
  • おまけ
    • railsコンテナ上でbinding.pryをする方法
    • railsコンテナ上でbundle installした時に、変更内容をコンテナ上に反映させる方法

コンテナ起動までの大まかな流れ

DockerfileにてRubyのベースイメージをもとにイメージを作成する

作成したイメージをもとにdocker-compose.ymlでappコンテナを作成すると同時に、DBのコンテナのイメージを作成し、これらのコンテナを連携させる

database.ymlを修正してappコンテナからdbコンテナへ接続できるように設定する

実際の作業

  1. Dockerfileとdocker-compose.ymlの作成
  2. Dockerfileの記載
  3. docker-compose.ymlの記載
  4. database.ymlの変更

1. Dockerfileとdocker-compose.ymlの作成

まず、開発しているアプリで、Dockerfileとdocker-compose.ymlを以下のように作成します。

アプリ名
  |- app
  |- bin
  |- config
      #略
  |- vendor
  - .gitignore
  - config.rb
  - Dockerfile           #追加
  - docker-compose.yml  #追加
  - Gemfile
  - Gemfile.lock
      #略

2. Dockerfileの記載

続いてDockerfileの中身を書いていきます。
myprojectのところはコンテナ起動の際に作成するディレクトリ名なので、何でも大丈夫です
ただし、それ以降の記述でも随時書き換えてください

Dockerfile
FROM ruby:2.5.1

RUN apt-get update && \
    apt-get install -y mysql-client nodejs vim --no-install-recommends && \
    rm -rf /var/lib/apt/lists/*

RUN mkdir /myproject

WORKDIR /myproject

ADD Gemfile /myproject/Gemfile
ADD Gemfile.lock /myproject/Gemfile.lock

RUN gem install bundler
RUN bundle install

ADD . /myproject

詳細な説明は省きますが、ざっと説明すると

  • ruby2.5.1をベースイメージとする
  • コンテナ内で必要なコマンドをインストール
  • myprojectというディレクトリを作成して基点にする
  • Gemfileをコンテナ上にコピーした後、bundle install
  • ローカルのディレクトリ、ファイルをコンテナ上にコピー

という感じかと思います。

3. docker-compose.ymlの記載

Rubyのコンテナは作成できるようになりました。
続いてこれをもとにアプリケーションのコンテナとデータベースのコンテナを作成し、それらのコンテナをリンクさせるための作業をしていきます。
docker-compose.ymlを以下のように記載します。
*mysqlは8.0以上だと認証方法が異なるようなので注意
https://qiita.com/yensaki/items/9e453b7320ca2d0461c7

docker-compose.yml
version: '2'
services:
  db:
    image: mysql:5.6
    volumes:
      - mysql-data:/var/lib/mysql    #データの永続化のために必要
    ports:
      - "4306:3306"  #両方3306でもok。詳細は下の「番外編:DBをsequel proで可視化したい」へ

  app:
    tty: true          #コンテナ上でbinding.pryするために必要
    stdin_open: true   #コンテナ上でbinding.pryするために必要
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myproject    #ローカルのディレクトリをコンテナ上にマウント
      - bundle:/usr/local/bundle    #bundle installした後buildし直さなくてよくなる
    links:
      - db

volumes:
  mysql-data:
  bundle:      #bundle installした後buildし直さなくてよくなる

要点は以下

  • versionは2でも3でもいいと思いますが、使えるコマンドが違ってくるみたいです。
  • servicesのところにdbとappがありますが、これらがそれぞれコンテナになります。
  • appのコンテナのlinksにdbがあり、これによってappコンテナとdbコンテナが連携できるようになります
  • 一番下のvolumesには永続化させたいデータを記載
  • appコンテナ上でvolumes: - .:/myprojectとすることで、ローカルのディレクトリをマウントしている。
  • dbコンテナ上でvolumes: -mysql-data:/var/lib/mysqlとすることでデータベースで変更されたデータを永続化。この記述がないと、コンテナを壊した時に変更したデータが消えてしまいます。
  • bundle installとbinding.pryのための記述は本記事、最後のおまけを参照

4. database.ymlの変更

これまでの作業でappコンテナとdbコンテナを連携させる設定をしました。
最後にappコンテナからdbコンテナに接続するために、接続設定をします。
database.ymlの中身はおそらく初期設定のままだとこんな感じの記述になってるかと思います。

config/database.yml変更前
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

このままだとsocket通信でDB接続をするので、せっかく作成したdbコンテナが意味なくなってしまいます。
作成したdbコンテナに接続するために以下のように変更します。

config/database.yml変更後
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:password
  host: db   #変更(docker-compose.ymlのservice名を記載)

usernameやpasswordは環境変数で設定している記事もいくつか見ますが、開発環境なら気にしなくてもいいかなと思いました。
本番環境ではちゃんと環境変数を設定します。

以上で準備ができました。
あとはターミナルで該当アプリのディレクトリまで移動して、docker-compose upと入力するだけです
(Gemfile.lockの中身を削除して空にしないとエラーになるかもしれません)
localhost:3000で接続確認して終了です!

今回はMySQLを使いましたが、他のDBでも可能なはずです(未検証)
*ポート番号は変わるはずなのでご注意ください

番外編:DBをsequel proで可視化したい

今まで開発していた時、DBをsequel proで可視化していて便利だったのですが、docker上のDBも可視化したい!
という方に向けて以下に方法を記載します

docker-compose.ymlで以下のように記載していました
Ruby:docker-compose.yml
db:
ports:
- "4306:3306"

これはホストが4306で接続した時にコンテナ上では3306に置き換えますという意味です。
準備はこれでokなのでsequel proで接続します。
sequel proを開いて、標準タブに切り替えます。
そこで以下の内容を入力します

名前: 任意、変えなくてもok
ホスト: 127.0.0.1
ユーザー名: root (database.ymlに記載のユーザー名)
パスワード: password (database.ymlにパスワード)
データベース: 空でok
ポート: 4306(docker-compose.ymlのportsに記載した左側)

ホストの127.0.0.1は自分自身を表すIPアドレス

これで見れるようになるはず!

その他開発する上で必要なコマンド

docker上でrails g controllerやrails db:migrateなどを行う時は以下のようにコンテナを通して入力します
appの部分はdocker-compose.ymlで作成したコンテナ名のappのことです

docker-compose run --rm app 入力したいコマンド(例: rails db:migrate)

その他必要なコマンドは以下の記事参照
https://qiita.com/gold-kou/items/44860fbda1a34a001fc1



全てのコンテナやイメージを削除する場合はこちら

#全てのコンテナ停止
docker stop $(docker ps -q)

#全てのコンテナ削除
docker rm $(docker ps -q -a)

#全てのイメージ削除
docker rmi $(docker images -q)

おまけ

bundle installしたい時

開発していく中で、gemを追加してbundle installしたい場面が出てくると思います
そのままやってもできるんですが、追加したgem内容がコンテナ内に反映されないため、イメージをbuildし直さなくてはなりません。
いくつか解決方法はあるみたいですが、今回はvolumeでマウントするという方法で解決しました。

docker-compose.yml
app:
  volumes:
    - bundle:/usr/local/bundle

   #中略

volumes:
  bundle:

参考記事
https://qiita.com/neko-neko/items/abe912eba9c113fd527e

bindin.pryしたい時

binding.pryをするためには以下の記述を追加します

docker-compose.yml
app:
  tty: true
  stdin_open: true

おわりに

dockerについて全くわからないところから環境構築するのはかなり大変でした
自分なりにまとめられて良かった
同じような状況の人の参考になれば幸いです

間違ってる場所があれば指摘していただけると幸いです

本番環境でDockerを使うのも苦労したので、そのうち開発環境との違いなどもまとめようかなと思います

参考記事

Dockerについての概要と色々なTIPSを知りたい場合は下記リンクがおすすめ
https://qiita.com/gold-kou/items/44860fbda1a34a001fc1

実際の作業で参考にした記事
https://qiita.com/azul915/items/5b7063cbc80192343fc0
https://qiita.com/Nishi53454367/items/aee4cf0c346bc115be99

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

Dockerで始めるLaravel講座 - Docker編

はじめに

気づけばオリンピックイヤーである2020年がしれっと始まりましたが皆様いかがお過ごしでしょうか。
さて、今日は「Dockerで始めるLaravel講座」のDocker編です。
今日はサクサクっとどうやってDockerを使うのかを学んでいきましょう。


アジェンダ

今日はこんな順番でお話していきます。

  1. Dockerをはじめてみよう
  2. docker-composeでより本番に近づけてみよう

Dockerをはじめてみよう


Kitematicを入れてみよう

Dockerがまずピンときてないときは、まずはピンときてしまうことです。
そのためにDockerには Kitematic(カイトマティック) という素晴らしいGUIダッシュボードツールがあります。

最新版はこちらからダウンロードできます。
https://github.com/docker/kitematic/releases


なんとかかんとかインストールして開いてみるとこんな画面になると思います。
image.png


せっかくなので、ここからApache(httpd)でも立ち上げてみましょう。
Search for Docker images ~ と書かれている検索ボックスに httpd と入れてみましょう。
するとこんな感じになると思います。
image.png


では、ここで左上のofficial httpdと書かれているボックスの右下にあるCREATEをクリックしてみましょう。
すると何やらダウンロードを始めて、謎のコンソール画面が出てくると思います。


そう、何を隠そう、これで実はApacheのDockerコンテナが立ち上がっている状態なのです。
試しに右上のHome Settings と書かれているタブをSettingsに切り替えてから中のタブをHostname/Portsに切り替えてConfigure Portslocalhost:xxxxと書かれているところをクリックしてみましょう。


こんな感じです。
image.png


するとブラウザにIt works!と表示されているはずです。
おめでとう! Apacheが立ち上がっていますね!


せっかくApache立ち上がったのでApacheの中に入ってみましょうか。
Kitematicに戻ってみると EXEC って書いてあるところがあるのでポチーしてみましょう。
image.png


するとなにやら黒い画面が現れてきます。
そう、これでDockerで立ち上げた仮想環境の中に入っているのです。

せっかくなので、入ってる気分を体験してみましょう。


こちらのコマンドを順に打ち込んでみてください。

$ apt update
$ apt install -y vim
$ cd htdocs
$ vi index.html

すると、さっき表示していた It Works! の文字を表示していたHTMLファイルが開けます。
こいつをちょちょいと弄ってみてさっきのブラウザをリロードしてみましょう。

表示、変わりましたか?


ではもう用済みなので、このコンテナは消してやりましょう。
Kitematicのここをクリックしてみてください。
image.png


ローカルのファイルをDockerコンテナに反映させよう

コンテナでただ遊ぶ分にはさっきの方法でもいいのですが、ちゃんと開発で使おう!と思うといちいちコンテナの中に入ってvimでファイルを開いて編集……というやり方でやってたら全然効率がよくありません。
やっぱ「Dockerやめて素直にXAMPP使うぜ」になってしまいます。


じゃあどうしたらいいのか。
VirtualBoxとかVagrantで仮想環境を使った開発をしたことある人ならもうピンときていると思いますが「共有フォルダ」機能を使えばいいのです。
ちゃんとDockerにもありますよ!
ただこれ、Kitematicからは設定できないので、コマンドラインから実行する必要があります。


Kitematicの画面の左下に DOCKER CLI と書かれたボタンが有るの分かりますか? そこをポチーしてみましょう。
image.png


実行する環境によって出てくるものが若干違うと思いますが、これまた黒い画面が現れてきます。
Windowsならコマンドプロンプトが、Macならターミナルの画面が出てきてると思います。
多分なんとなくわかったと思いますが、実はKitematicなど使わなくてもDockerは使えます。

あ、知ってましたかね?


ではデスクトップに docker-test というフォルダを作って中に index.html を作ってみてください。
index.htmlの内容は何でもいいです。
HTMLの書き方がわからなければ下をコピペしてください。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Test</title>
</head>
<body>
    やったねたえちゃん、家族が増えたよ
</body>
</html>

できたらターミナルの画面でなんとかかんとかデスクトップまでたどり着いてください。
そこで下記コマンドを入力してみてください。

docker run -v $(pwd)/docker-test:/usr/local/apache2/htdocs -d -p 8080:80 httpd

今度はブラウザで http://localhost:8080 を開いてみてください。
さっき作ったやつになりましたよね?


docker-composeでより本番に近づけてみよう


そもそもなんでDockerを使うのか

割と肝心の話をしてなかったような気がしますね。
当たり前なのですが、Web開発におけるローカル開発環境の手段はDockerだけではありません。
大まかには以下の3通りのどれかになるかと思います。

  • ローカルのOSにApache/PHP/MySQLなどのミドルウェアを直接入れて開発する
  • VirtualBoxなどのVM型仮想環境を使う
  • Dockerなどのコンテナ型仮想環境を使う

それぞれにメリット・デメリットはあるのですが、大体のケースに置いてDockerはおすすめです。


かんたんにメリット・デメリットまとめるとこんな感じですかね。

方法 メリット デメリット
直ミドルウェア かんたん(何なら最初から入ってることも) 環境が汚れてしまうので複数案件まわせない。たくさん建てるのは無理
VM どこでも安定して動く。 おもい。たくさん立てるのが大変(できないことはない)
コンテナ サクサク立てられる。一度にたくさん立てられる 一部できないことがある

つまり、たくさん立てないといけないときはほぼDocker一択という選択になります。

僕が初めてDockerを仕事で作ったときはこんな構成でした。

image.png
APIサーバーと管理画面サーバーが同じDBにアクセスする構成ですね。


こんな感じの構成をちゃちゃっと作るのにはDockerの一機能である docker-compose というのが威力を発揮します。
いや、まあ、 kubernetes とかもあるっちゃあるのですが、それはまたどこかでやりましょう。


ではさっき作ったtest-dockerフォルダの中にこんな内容の docker-compose.yml を作ってみてください。

version: '2.1'
services:
  mysql:
    image: mysql:5.6
    volumes:
      - './mysql/var/log/mysql:/var/lib/mysql'
    ports:
      - '4306:3306'
    environment:
      MYSQL_ROOT_PASSWORD: rootPass11111111
      MYSQL_DATABASE: laratest
      MYSQL_USER: larauser
      MYSQL_PASSWORD: larapass
  api:
    image: httpd
    links:
      - mysql
    ports:
      - '8081:80'
    volumes:
      - './api:/usr/local/apache2/htdocs'
  admin:
    image: httpd
    links:
      - mysql
    ports:
      - '8082:80'
    volumes:
      - './admin:/usr/local/apache2/htdocs'

できたらこんどは、apiとadminディレクトリを作ってそこにindex.htmlをおいてみましょう。
内容はちょこっとだけ変えたほうが良いですね。

image.png
こんな感じになりましたか?


では、docker-composeを起動してみましょう。

こちらのコマンドを打ち込んでみてください。

$ docker-compose up -d

すると楽しいことが起きていると思います。


Kitematicを見てみると一気に3つコンテナが立ち上がってるのがわかると思います。
こうすることによってマルチコンテナ構成を簡単に作れるのです。


次回はこのDocker環境を使ってLaravelのアプリケーションを作っていきたいと思います。

おつかれさまでした!

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

コマンドラインからDocker Hubで公開されているイメージの「タグ」を検索するためのツールを作りました

はじめに

Docker で開発をすすめる機会が増えてくると、だんだん「タグ」を調べることが多くなってきます。

Docker における タグ とは、たとえば MySQL公式イメージを利用する際に mysql:8.0.18 のように指定する コロン の後ろの部分になります。

同じDockerイメージでも、 「タグ」 の違いにより機能が異なります。
PHPでも FPM 対応もの、 Apache 対応のもの、 コマンドラインだけで動作するものなどが用意されており、それぞれ以下の用意なっています。

  • php:fpm
  • php:apache
  • php:cli

「タグ」を覚えたり調べたりは面倒

「タグ」を調べるにはどうしたらよいでしょう?

Docker Hub のサイトで該当イメージを探し、タグの値を探せばよいです。

しかし、せっかくコーディングがフロー状態に入ってきたり、あるいは CUIの世界から出たくない! という方々も多いと思います。

コマンドラインから「タグ」を検索するツールを作った

そこでDockerの学習も兼ねて「タグ」を検索するツールを作りました。

genzouw/docker-tags - GitHub

ツール自体も Docker で動きます。
ですので、 docker コマンドをコマンドラインから利用できるようにしてください。

使い方

機能自体が少ないので、 Github上のREADME を見ていただければ1分でわかるかと思います。

-h オプションを指定して実行した結果だけ、貼り付けておきます。

docker-tags [-p PAGE] [-a] [-h]
    -p : Output the specified number of pages.( DEFAULT : 5 )
    -a : Output all pages.
    -h : Output Help.

デフォルトでは5ページ(50タグ)分が出力されますが、 -f オプションあるいは -p オプションで件数を変更できます。

実行結果は以下のようになります。

TAG                           SIZE      UPDATED
-----                        -----      -----
latest                   134026357      2019-12-29T01:03:04.158114Z
8.0.18                   134026357      2019-12-29T01:03:02.024679Z
8.0                      134026357      2019-12-29T01:03:00.45482Z
8                        134026357      2019-12-29T01:02:58.07512Z
5.7.28                   150505380      2019-12-29T01:02:46.654066Z
5.7                      150505380      2019-12-29T01:02:44.854124Z
5.6.46                   102683838      2019-12-29T01:02:42.938573Z
5.6                      102683838      2019-12-29T01:02:38.761685Z
5                        150505380      2019-12-29T01:02:22.579441Z
8.0.17                   129970553      2019-09-12T06:03:06.99785Z
5.7.27                   124130524      2019-09-12T06:02:47.200186Z
5.6.45                    82841471      2019-09-12T06:02:42.262232Z
8.0.16                   129388433      2019-07-17T22:47:34.737755Z
5.7.26                   124147701      2019-07-17T22:47:18.044464Z
5.6.44                    82831221      2019-07-17T22:47:12.767655Z
5.5.62                    66072546      2019-05-10T23:43:35.219656Z
...

ひとこと

フィードバッグお待ちしております。

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

GCE上でContainer-Optimized OSを使ってコンテナバッチ処理する方法

Container-Optimized OSを使ってGCE上でコンテナバッチ処理する方法のメモ。
コンテナバッチ処理後はコンテナ内でVMを削除するため、VM稼働分のコストで済みます。
コードはGithubにあげています。
https://github.com/yolo-kiyoshi/gce_docker_cli

フォルダ構成
root/
 ├ .env
 ├ .param
 ├ Dockerfile
 ├ Pipfile
 ├ Pipfile.lock
 ├ *********.json(credentialファイル)
 ├ scripts/
 │ └ build_and_push.sh
 │ └ deploy_container.sh
 └ src/
   └ delete_vm.py
   └ main.py

準備

VM起動パラメータ

VM起動パラメータを .param に記載します。

SERVICE_ACCOUNT=*********
PROJECT_ID=*********
MACHINE_TYPE=n1-standard-1

Credentialファイル

Dockerfile と同一ディレクトリにCredentialファイル(json)を配置します。

コンテナ環境変数

コンテナ環境変数を .env に記載します。
Credentialファイル(json)pathを必ず GOOGLE_APPLICATION_CREDENTIALS に記載します。

GOOGLE_APPLICATION_CREDENTIALS=/app/************.json

概要

  1. GCRにDockerイメージをプッシュ
  2. GCRのイメージからGCE上のVMにコンテナをデプロイ。コンテナ処理終了後、VMを削除

GCRにDockerイメージをプッシュ

Dockerイメージをビルドし、GCRにイメージをプッシュするスクリプトです。

scripts/build_and_push.sh
#!/usr/bin/env bash

set -eu

image=${1:-}
tag=${2:-latest}

# read param
. .param

fullname="gcr.io/${PROJECT_ID}/${image}:${tag}"

# read setting file
docker build -t ${image}:${tag} .
docker tag ${image}:${tag} ${fullname}
docker push ${fullname}
echo "image successfully pushed to: ${fullname}"

Dockerfile と同一ディレクトリで以下を実行すると、GCRにDockerイメージをプッシュできます。

Dockerビルド&GCRへのプッシュ
sh scripts/build_and_push.sh <イメージ名> <タグ>

GCRのイメージからGCE上のVMにコンテナをデプロイ。コンテナ処理終了後、VMを削除

GCRのイメージからGCE上のVMにコンテナをデプロイするスクリプトです。

deploy_container.sh
#!/usr/bin/env bash

set -eu

service=${1:-}
image=${2:-}
tag=${3:-latest}

# read param
. .param

fullname="gcr.io/${PROJECT_ID}/${image}:${tag}"

gcloud compute instances create-with-container ${service} \
    --container-image=${fullname} \
    --container-env-file=.env \
    --container-restart-policy=never \
    --machine-type=${MACHINE_TYPE} \
    --service-account=${SERVICE_ACCOUNT}

VMを削除するモジュールです。

src/delete_vm.py
from googleapiclient import discovery

from oauth2client.client import GoogleCredentials

import requests


def delete_vm():
    # credentialオブジェクト取得
    credentials = GoogleCredentials.get_application_default()
    service = discovery.build('compute', 'v1', credentials=credentials)
    # メタデータサーバからプロジェクトID, インスタンンス名, ゾーンを取得する
    project_id = requests.get(
        "http://metadata.google.internal/computeMetadata/v1/project/project-id",
        headers={"Metadata-Flavor": "Google"}
    ).text
    name = requests.get(
        "http://metadata.google.internal/computeMetadata/v1/instance/name",
        headers={"Metadata-Flavor": "Google"}
    ).text
    zone_long = requests.get(
        "http://metadata.google.internal/computeMetadata/v1/instance/zone",
        headers={"Metadata-Flavor": "Google"}
    ).text
    zone = zone_long.split("/")[-1]

    print(f'[delete target] project_id:{project_id},name:{name},zone:{zone}')
    # VMインスタンス削除
    request = service.instances().delete(
        project=project_id,
        zone=zone,
        instance=name
    )
    request.execute()

main の最後(finally)でVM削除処理を行います。

src/main.py
from delete_vm import delete_vm


try:
    print('process start.')
    ######################
    # process
    ######################
    print('process end.')
finally:
    delete_vm()

Dockerfile と同一ディレクトリで以下を実行すると、GCRのDockerイメージをもとにVMにコンテナをデプロイします。
コンテナ内での処理終了後はVMを削除します。

sh scripts/deploy_container.sh <サービス名> <イメージ名> <タグ>

参考

How to make GCE instance stop when its deployed container finishes?
Google公式ドキュメント

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