- 投稿日:2020-02-08T20:17:50+09:00
とりあえずLaradockで
対象者
とりあえずインフラとかDockerとか慣れてなくてよく分からないけど、手早くLaravelを動かせればいいやーって人向けです。
Laradockとは
公式サイトには「Laradockは、Dockerに基づく完全なPHP開発環境です。」とあります。
Laradock is a full PHP development environment based on Docker.
公式
前提
- パソコンがある
- Wifiがある
※あとDockerのいんすとーるとかはやっといてくださーい、gitも要るよー。
手順
1. ローカルでディレクトリを作成
- 任意のディレクトリ作成
$ mkdir laradock $ cd laradock/2. LaradockのリポジトリをClone
GithubからLaradockのリポジトリをクローン
$ git clone https://github.com/Laradock/laradock.git laradock-practice $ cd laradock-practice/laradock-practiceの部分は、好きに変えてください。
デフォルトでは「laradock」というディレクトリになりますが、引数に名前を渡すとオリジナルのものができあがります。名前はつけておいたほうがいいっすね。3. 各種設定 (Laradock)
- 設定ファイルのコピー作成
$ cp env-example .env.env(設定ファイル)を開く
$ vi .env以下の項目を探し、修正してください
修正前
APP_CODE_PATH_HOST=../修正後
APP_CODE_PATH_HOST=../laradock-projectlaradock-projectの部分はこれから作るLaravelプロジェクトの名前にしてください。
LaravelのWebサーバー上で同期するディレクトリを指定しています。
これをちゃんと指定してあげないとアクセス時404エラーになります。※viコマンドはコマンドでファイルの編集ができます。編集したい箇所で「i」を入力するとインサートモードになり文字が打てるようになります。インサートモードを終了するには「esc」ボタンを入力します。その後、編集したファイルを保存し、終了するには「:」と「wq」を立て続けに入力してください。
修正前
MYSQL_VERSION=latest MYSQL_DATABASE=default MYSQL_USER=default MYSQL_PASSWORD=secret MYSQL_PORT=3306 MYSQL_ROOT_PASSWORD=root修正後
MYSQL_VERSION=5.7(別に5.7じゃなくても) MYSQL_DATABASE=このへんは MYSQL_USER=じゆうに MYSQL_PASSWORD=きめちゃってください MYSQL_PORT=3306 MYSQL_ROOT_PASSWORD=root※詳しく調べていませんが、mysqlのverをlatestで最新にするとセキュリティ上の問題でうまく接続できないらしいです。僕はちなみに、5.7にしているのにうまく動かない時があり、なぜだろうと思っていたら「5.7t」と記述しており、5.7トンという重さを指定してしまっていたことがありました。
- laradock-practice/nginx/sites/default.confの変更
これはnginxに関する設定ファイルです。
nginx起動時に表示するファイルなどを指定できるのですが、パスの指定がうまくいっていない場合があるので、修正する必要があれば書き換えましょう。
着目してもらいたいのは一部分です。
以下のような修正前の状態になっていれば、修正してください。
laradock-projectの部分はそれぞれ作成されるLaravelプロジェクトの名前を指定してください。修正前
root /var/www/public;修正後
root /var/www/laradock-project/public;4. コンテナ立ち上げ〜プロジェクトの作成
- コンテナの立ち上げ
$ docker-compose up -d mysql nginxdocker-compose upコマンドはdocker-compose.ymlに書かれた情報をもとに処理を実行します(コンテナイメージの作成からコンテナの立ち上げなど。引数なしだと記述されている内容すべてが実行されるので、ひとまずDBサーバのmysqlとwebサーバのnginxを指定します。
※-dはデタッチモード(バックグラウンドで起動します)
- コンテナの起動確認
以下のように立ち上がっていれば大丈夫です。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 82e444c0ae67 laradock_nginx "/bin/bash /opt/star…" 6 seconds ago Up 4 seconds 0.0.0.0:80-81->80-81/tcp, 0.0.0.0:443->443/tcp laradock_nginx_1 bd531621d6a3 laradock_php-fpm "docker-php-entrypoi…" 7 seconds ago Up 6 seconds 9000/tcp laradock_php-fpm_1 1665d8a83f3b laradock_workspace "/sbin/my_init" 8 seconds ago Up 7 seconds 0.0.0.0:2222->22/tcp laradock_workspace_1 d8b22e74c28f docker:dind "dockerd-entrypoint.…" 10 seconds ago Up 8 seconds 2375-2376/tcp laradock_docker-in-docker_1 7af2df7ebe17 laradock_mysql "docker-entrypoint.s…" 10 seconds ago Up 8 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp laradock_mysql_1
- ワークスペースコンテナに入る
ワークスペースコンテナに入ります。exec、bashでそのコンテナに対してコマンドが叩けるようになります。
ワークスペースとはLaravelの開発を進めるにあたって必要なcomposerなどのツール類が用意された作業スペースみたいなところです。
デフォルトだとrootでワークスペースに入ることになるのですが、後ほどcomposerコマンドを実行した際に、怒られてしまうので、怒られるのが苦手な人は--user=laradockとかでlaradockユーザーとしてワークスペースに入ってください。
$ docker-compose exec --user=laradock workspace bash .../var/www$
- Laravelプロジェクトの作成
以下のコマンドで、Laravelのプロジェクトがlaradockディレクトリと同じ階層の中に作成されます。
この実行内容だと最新verのLaravelでプロジェクトが作られます。ver指定したい場合は調べてください。.../var/www$ composer create-project laravel/laravel laradock-project ...以下略 Application key set successfully.
- プロジェクト内へ移動
プロジェクト内に移動します。
.../var/www$ cd laradock-project/5. 各種設定(Laravelプロジェクト)
- 設定ファイルの修正
.../var/www$ vi .env以下のように修正
修正前
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD=修正後
DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=このへんはさっきつくった DB_USERNAME=Laradockの.envの内容と DB_PASSWORD=合わせてください.envの内容は先ほど作ったLaradockの方の内容と整合性が取れている必要がありますので合わせておいてください。
7. MySQLの確認
MySQLの設定がうまくいっているかを確認します。
- MySQLコンテナへ入る
Ctl + dでワークスペースコンテナを出て、MySQLコンテナに入ります。
$ docker-compose exec mysql bash
- MySQLへ接続
MySQLへ、接続します。defaultの部分は先ほど.envファイルで設定したユーザーネームを指定し、その後パスワードを聞かれるので、同じように.envで設定したパスワードを入力してください。うまくログインできればsqlコマンドが打てる画面に移り変わります。
# mysql -u default -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.7.27 MySQL Community Server (GPL) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
- データベースの確認
うまく設定できていれば、.envで設定したデータベースが作られているはずです
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | default | +--------------------+ 2 rows in set (0.02 sec)
- ユーザーの確認(rootで入った場合のみ行えます)
こちらも設定できていれば、.envで設定したユーザーが登録されていることが確認できますが、mysqlにroot権限で接続している必要があります。
mysql> select User from mysql.user; +---------------+ | User | +---------------+ | default | | root | | mysql.session | | mysql.sys | | root | +---------------+ 5 rows in set (0.02 sec)
- マイグレーションチェック
マイグレーションを実行し、データベースの接続が上手くいっているかを確認します。
Laravelにおけるマイグレーションとはデータベースのバージョン管理機能のことです。MySQL確認の延長ですが、一旦MySQLコンテナから抜け、ワークスペースコンテナに入り、プロジェクト内に移動して以下のコマンドを実行します。
データベース接続がうまくいっていればマイグレーションが実行されます。
$ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.07 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.06 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds)ここまでの流れで上手くいかない場合
- Laradock、Laravelプロジェクトの各.envファイルの整合性が取れていない可能性
→.envファイルの設定がそれぞれ同じになっているかを確認し、合っていなければ合わせてください。
- ストレージデータの影響
→laradockでDBを使用する際のストレージがデフォルトで、~/.laradock/dataに設定されています。~/.laradock/dataにmysqlというディレクトリが存在しているので一旦削除してやり直してみてください。
補足
デフォルトで~/.laradock/dataが設定されていると説明しましたが、これでは他にLaradockを使ってプロジェクトを作成した際に同じ場所を参照してしまうので変えた方がいいっぽいです。ここでは詳しく解説はしませんので詳細は調べてください。
- .envの書き換え等が反映されていない可能性
コンテナを立ち上げたまま、.env等の設定を書き換えただけでは内容が反映されません。
一度、コンテナを起動させ直しましょう。再起動
$ docker-compose restartダメなら停止と削除〜起動
$ docker-compose down$ docker-compose up -d mysql nginx8. プロジェクトの起動確認
- localhostへアクセス
nginxのコンテナを立ち上がっている状態でlocalhostへアクセスします。うまくいっていれば、Laravelのトップページが表示されます。
上手くいかない場合
- Laradockの.envファイルのAPP_CODE_PATH_HOSTの設定が正しくできていない
→プロジェクトが存在するパスをちゃんと記述してあげてください。
- nginxのdefault.confのパス指定が上手くできていない
→上記に手順を記載していますので、やり直してください。
- nginxコンテナが立ち上がっていない
→docker psコマンドで確認し、立ち上がっていなければ、立ち上げてください。
ここまでくればとりあえずの環境構築は完了です!
あとは煮るなり焼くなり好きにしてください!
- 投稿日:2020-02-08T20:17:50+09:00
とりあえずLaradock
対象者
とりあえずインフラとかDockerとか慣れてなくてよく分からないけど、手早くLaravelを動かせればいいやーって人向けです。
Laradockとは
公式サイトには「Laradockは、Dockerに基づく完全なPHP開発環境です。」とあります。
Laradock is a full PHP development environment based on Docker.
公式
前提
- パソコンがある
- Wifiがある
※あとDockerのいんすとーるとかはやっといてくださーい、gitも要るよー。
手順
1. ローカルでディレクトリを作成
- 任意のディレクトリ作成
$ mkdir laradock $ cd laradock/2. LaradockのリポジトリをClone
GithubからLaradockのリポジトリをクローン
$ git clone https://github.com/Laradock/laradock.git laradock-practice $ cd laradock-practice/laradock-practiceの部分は、好きに変えてください。
デフォルトでは「laradock」というディレクトリになりますが、引数に名前を渡すとオリジナルのものができあがります。名前はつけておいたほうがいいっすね。3. 各種設定 (Laradock)
- 設定ファイルのコピー作成
$ cp env-example .env.env(設定ファイル)を開く
$ vi .env以下の項目を探し、修正してください
修正前
APP_CODE_PATH_HOST=../修正後
APP_CODE_PATH_HOST=../laradock-projectlaradock-projectの部分はこれから作るLaravelプロジェクトの名前にしてください。
LaravelのWebサーバー上で同期するディレクトリを指定しています。
これをちゃんと指定してあげないとアクセス時404エラーになります。※viコマンドはコマンドでファイルの編集ができます。編集したい箇所で「i」を入力するとインサートモードになり文字が打てるようになります。インサートモードを終了するには「esc」ボタンを入力します。その後、編集したファイルを保存し、終了するには「:」と「wq」を立て続けに入力してください。
修正前
MYSQL_VERSION=latest MYSQL_DATABASE=default MYSQL_USER=default MYSQL_PASSWORD=secret MYSQL_PORT=3306 MYSQL_ROOT_PASSWORD=root修正後
MYSQL_VERSION=5.7(別に5.7じゃなくても) MYSQL_DATABASE=このへんは MYSQL_USER=じゆうに MYSQL_PASSWORD=きめちゃってください MYSQL_PORT=3306 MYSQL_ROOT_PASSWORD=root※詳しく調べていませんが、mysqlのverをlatestで最新にするとセキュリティ上の問題でうまく接続できないらしいです。僕はちなみに、5.7にしているのにうまく動かない時があり、なぜだろうと思っていたら「5.7t」と記述しており、5.7トンという重さを指定してしまっていたことがありました。
- laradock-practice/nginx/sites/default.confの変更
これはnginxに関する設定ファイルです。
nginx起動時に表示するファイルなどを指定できるのですが、パスの指定がうまくいっていない場合があるので、修正する必要があれば書き換えましょう。
着目してもらいたいのは一部分です。
以下のような修正前の状態になっていれば、修正してください。
laradock-projectの部分はそれぞれ作成されるLaravelプロジェクトの名前を指定してください。修正前
root /var/www/public;修正後
root /var/www/laradock-project/public;4. コンテナ立ち上げ〜プロジェクトの作成
- コンテナの立ち上げ
$ docker-compose up -d mysql nginxdocker-compose upコマンドはdocker-compose.ymlに書かれた情報をもとに処理を実行します(コンテナイメージの作成からコンテナの立ち上げなど。引数なしだと記述されている内容すべてが実行されるので、ひとまずDBサーバのmysqlとwebサーバのnginxを指定します。
※-dはデタッチモード(バックグラウンドで起動します)
- コンテナの起動確認
以下のように立ち上がっていれば大丈夫です。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 82e444c0ae67 laradock_nginx "/bin/bash /opt/star…" 6 seconds ago Up 4 seconds 0.0.0.0:80-81->80-81/tcp, 0.0.0.0:443->443/tcp laradock_nginx_1 bd531621d6a3 laradock_php-fpm "docker-php-entrypoi…" 7 seconds ago Up 6 seconds 9000/tcp laradock_php-fpm_1 1665d8a83f3b laradock_workspace "/sbin/my_init" 8 seconds ago Up 7 seconds 0.0.0.0:2222->22/tcp laradock_workspace_1 d8b22e74c28f docker:dind "dockerd-entrypoint.…" 10 seconds ago Up 8 seconds 2375-2376/tcp laradock_docker-in-docker_1 7af2df7ebe17 laradock_mysql "docker-entrypoint.s…" 10 seconds ago Up 8 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp laradock_mysql_1
- ワークスペースコンテナに入る
ワークスペースコンテナに入ります。exec、bashでそのコンテナに対してコマンドが叩けるようになります。
ワークスペースとはLaravelの開発を進めるにあたって必要なcomposerなどのツール類が用意された作業スペースみたいなところです。
デフォルトだとrootでワークスペースに入ることになるのですが、後ほどcomposerコマンドを実行した際に、怒られてしまうので、怒られるのが苦手な人は--user=laradockとかでlaradockユーザーとしてワークスペースに入ってください。
$ docker-compose exec --user=laradock workspace bash .../var/www$
- Laravelプロジェクトの作成
以下のコマンドで、Laravelのプロジェクトがlaradockディレクトリと同じ階層の中に作成されます。
この実行内容だと最新verのLaravelでプロジェクトが作られます。ver指定したい場合は調べてください。.../var/www$ composer create-project laravel/laravel laradock-project ...以下略 Application key set successfully.
- プロジェクト内へ移動
プロジェクト内に移動します。
.../var/www$ cd laradock-project/5. 各種設定(Laravelプロジェクト)
- 設定ファイルの修正
.../var/www$ vi .env
以下のように修正
修正前
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD=修正後
DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=このへんはさっきつくった DB_USERNAME=Laradockの.envの内容と DB_PASSWORD=合わせてください.envの内容は先ほど作ったLaradockの方の内容と整合性が取れている必要がありますので合わせておいてください。
7. MySQLの確認
MySQLの設定がうまくいっているかを確認します。
- MySQLコンテナへ入る
Ctl + dでワークスペースコンテナを出て、MySQLコンテナに入ります。
$ docker-compose exec mysql bash
- MySQLへ接続
MySQLへ、接続します。defaultの部分は先ほど.envファイルで設定したユーザーネームを指定し、その後パスワードを聞かれるので、同じように.envで設定したパスワードを入力してください。うまくログインできればsqlコマンドが打てる画面に移り変わります。
# mysql -u default -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.7.27 MySQL Community Server (GPL) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
- データベースの確認
うまく設定できていれば、.envで設定したデータベースが作られているはずです
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | default | +--------------------+ 2 rows in set (0.02 sec)
- ユーザーの確認(rootで入った場合のみ行えます)
こちらも設定できていれば、.envで設定したユーザーが登録されていることが確認できますが、mysqlにroot権限で接続している必要があります。
mysql> select User from mysql.user; +---------------+ | User | +---------------+ | default | | root | | mysql.session | | mysql.sys | | root | +---------------+ 5 rows in set (0.02 sec)
- マイグレーションチェック
マイグレーションを実行し、データベースの接続が上手くいっているかを確認します。
Laravelにおけるマイグレーションとはデータベースのバージョン管理機能のことです。MySQL確認の延長ですが、一旦MySQLコンテナから抜け、ワークスペースコンテナに入り、プロジェクト内に移動して以下のコマンドを実行します。
データベース接続がうまくいっていればマイグレーションが実行されます。
$ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.07 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.06 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds)ここまでの流れで上手くいかない場合
- Laradock、Laravelプロジェクトの各.envファイルの整合性が取れていない可能性
→.envファイルの設定がそれぞれ同じになっているかを確認し、合っていなければ合わせてください。
- ストレージデータの影響
→laradockでDBを使用する際のストレージがデフォルトで、~/.laradock/dataに設定されています。~/.laradock/dataにmysqlというディレクトリが存在しているので一旦削除してやり直してみてください。
補足
デフォルトで~/.laradock/dataが設定されていると説明しましたが、これでは他にLaradockを使ってプロジェクトを作成した際に同じ場所を参照してしまうので変えた方がいいっぽいです。ここでは詳しく解説はしませんので詳細は調べてください。
- .envの書き換え等が反映されていない可能性
コンテナを立ち上げたまま、.env等の設定を書き換えただけでは内容が反映されません。
一度、コンテナを起動させ直しましょう。再起動
$ docker-compose restartダメなら停止と削除〜起動
$ docker-compose down$ docker-compose up -d mysql nginx8. プロジェクトの起動確認
- localhostへアクセス
nginxのコンテナを立ち上がっている状態でlocalhostへアクセスします。うまくいっていれば、Laravelのトップページが表示されます。
上手くいかない場合
- Laradockの.envファイルのAPP_CODE_PATH_HOSTの設定が正しくできていない
→プロジェクトが存在するパスをちゃんと記述してあげてください。
- nginxのdefault.confのパス指定が上手くできていない
→上記に手順を記載していますので、やり直してください。
- nginxコンテナが立ち上がっていない
→docker psコマンドで確認し、立ち上がっていなければ、立ち上げてください。
ここまでくればとりあえずの環境構築は完了です!
あとは煮るなり焼くなり好きにしてください!
- 投稿日:2020-02-08T19:35:23+09:00
【docker】docker試煉日(1)
目的
熟悉與掌握docker用法,實作出內部測試環境與降低多環境需求之成本
Docker 架構
Docker 包括三個基本元素:
- 鏡像(Image):Docker 鏡像(Image),就相當於是一個 root 文件系統。比如官方鏡像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系統的 root 文件系統。
- 容器(Container):鏡像(Image)和容器(Container)的關係,就像是VM安裝概念一樣,鏡像是靜態的定義,容器是鏡像運行時的實體。容器可以被創建、啟動、停止、刪除、暫停等,隨時可依據需求啟動一個你所需要的容器(Ubuntu CentOS等)。
- 倉庫(Repository):倉庫可視為一個程式碼控制中心,用來保存鏡像。 Docker 使用客戶端-服務器 (C/S) 架構模式,使用遠端API來管理和創建Docker容器。
Docker 容器通過 Docker 鏡像來創建。
安裝方法
https://www.runoob.com/docker/centos-docker-install.html
起手式
當安裝完成docker 都要先來跑跑看是否已經能正常運行
接下來我們就開始運行我們的第一個Docker吧P-MP15:~ puwu$ docker run ubuntu:15.10 /bin/echo "Hello world" Unable to find image 'ubuntu:15.10' locally 15.10: Pulling from library/ubuntu 7dcf5a444392: Pull complete 759aa75f3cee: Pull complete 3fa871dc8a2b: Pull complete 224c42ae46e7: Pull complete Digest: sha256:02521a2d079595241c6793b2044f02eecf294034f31d6e235ac4b2b54ffc41f3 Status: Downloaded newer image for ubuntu:15.10 Hello world好的,我們今天終於完成第一項任務,可以讓我的使用docker 幫我們印出Hello world
這是多麼不容易的事情(?)接下來讓我們了解一下啟動時參數使用的用途
使用docker鏡像nginx:latest以後台模式啟動一个容器,并將容器命名為mynginx。
docker run --name mynginx -d nginx:latest使用鏡像nginx:latest以後臺模式啟動壹個容器,將容器的80端口映射到主機的80端口,主機的目錄/data映射到容器的/data
docker run -p 80:80 -v /data:/data -d nginx:latest使用鏡像nginx:latest以互動模式啟動一個容器,在容器內執行/bin/bash命令。
P-MP15:~ puwu$ docker run -it nginx:latest /bin/bash root@fecf799928e4:/#更多詳細的參數可以參考HERE
背景服務與操作可參考這篇(後續再補上)HERE
- 投稿日:2020-02-08T19:23:03+09:00
コード書いたことないPdMやPOに捧ぐ、Rails on Dockerハンズオン vol.4 - Static pages -
この記事はなにか?
この記事は私が社内のプログラミング未経験者、ビギナー向けに開催しているRuby on Rails on Dockerハンズオンの内容をまとめたものです。ていうかこの記事を基にそのままハンズオンします。ハンズオンは
1回の内容は喋りながらやると大体40~50分くらいになっています。お昼休みに有志でやっているからです。
現在進行形なので週1ペースで記事投稿していけるように頑張ります。
ビギナーの方のお役にたったり、同じように有志のハンズオンをしようとしている人の参考になれば幸いです。
他のハンズオンへのリンク
・ Vol.1 - Introduction -
・ Vol.2 - Hello, Rails on Docker -
・ Vol.3 - Scaffold, RESTful, MVC -
・ Vol.4 - Static pages -
$
,#
,>
について
$
: ローカルでコマンドを実行するときは、頭に$
をつけています。
#
: コンテナの中でコマンドを実行するときは、頭に#
をつけています。
>
: Rails console内でコマンド(Rubyプログラム)を実行するときは、頭に>
をつけています。
はじめに
第4回目は、Static pages(静的なページ)を作ることにチャレンジしてみましょう!
そもそも静的なページとは、アクセスするユーザーや時間帯に関係なく同じコンテンツが表示されるページのことです。対義語は動的なページは例えばマイページのようなユーザーごとにコンテンツが変わってくるようなページのことですね。
静的なページのみで構築されているサイトを『Webサイト』、動的なページも存在するサイトを『Webアプリケーション』と呼び分けたりします。今回は、静的なトップページを作っていきますよ!
Railsの初期設定
とその前に。
今回は日本で使われ日本で運用するアプリを想定するのですが、Railsはデフォルトでは英語が使われていたりUTC(協定世界時)が使われていたりと、そのまま日本でサービス展開しようとすると面倒な部分があります。
最初にこの設定をローカライズ(日本化)しておきましょう!Timezoneの設定
Dockerfile
やdocker-compose.yml
でコンテナのタイムゾーンは日本に設定していましたね(TZ=Asia/Tokyo
)。Railsアプリも同じように設定してあげます。config/application.rb... class Application < Rails::Application ... config.time_zone = 'Tokyo' config.active_record.default_timezone = :local ... end
time_zone
はRailsアプリが時間を扱うときにどのtimezoneで動くかを指定する設定でデフォルトだとUTCになってます。例えばTime.current
で現在の時間を表示できたりするのですが、この結果をどのtimezoneで表示するかがこの設定で決まります。この後、Modelを保存したりするときなどもその作成日時などがこのtimezoneで設定されます。
active_record.default_timezone
はDBに書き込まれている時間をどのtimezoneとして扱うかの設定です。言語の設定
Railsではエラーメッセージなどが準備されているのですが、デフォルトでは英語で定義されています。日本でサービス展開する場合「?」となってしまうので、日本語化します。
config/application.rb... class Application < Rails::Application ... config.i18n.default_locale = :ja ... endこの設定で、
config/locales/
にあるyamlファイルの中からja:
で定義されている文字列が表示されるようになるんです。日本語版のファイルを作ってくださっている方がいらっしゃいますのでベースとして利用させていただきましょう。rails-i18n/ja.yml at master · svenfuchs/rails-i18n
こちらのファイルを
config/locales/ja.yml
として保存することで日本語化完了です!ちなみに『i18n』は『internationalization』のことで『国際化』と訳されます。アクセスする国によって時間や言語を変えたりすることです(今回は日本オンリーに対応ですが...笑い)。頭の『i』とお尻の『n』の間に18文字あるので『i18n』と表現します。技術系だとこういうの最近多いっすよね?
Bootstrap
まだまだ静的なページの作成には入りませんよ!次は、Bootstrapを使えるようにしていきましょう。
BootstrapはTwitter社が開発したCSSフレームワークです。
レスポンシブデザインに標準で対応されており、CSSだけでなくJavascript(jQuery)も含まれています。
多くの人に使われているためインターネット上に情報があふれていますので初心者にも安心です。一方で、多くの人に使われているため似通ったデザインになってしまうので少し慣れてくると敬遠されがちな印象です。Boostrapをyarnでインストール
Rails5まではgemでインストールするのが主流だったと思うのですが、Rails6ではWebpackerが必須になったこともありパッケージマネージャー経由でインストールするのが主流になっていくと思われますのでその方法で。
まだコンテナを立ち上げていなかったですね。それではコンテナを立ち上げてコンテナの中でコマンドを実行していきましょう!
$ docker-compose up -d $ docker-compose exec web ash# yarn add bootstrap jquery popper.jsこれでBootstrap関連のライブラリをインストールできたのでRailsアプリで使えるように設定していきます。
まずapplication.jsでBootstrapを読み込みます。
app/javascript/packs/application.js... require("bootstrap") ...次にBootstrapをSCSSで読み込むために
application.css
をapplication.scss
にリネームします。# mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scssファイルの中身はCSSの記法で書かれているものなので一度全て削除して以下のように書き換えましょう。
app/assets/stylesheets/application.scss@import 'bootstrap/scss/bootstrap';最後にBootstrapと依存関係にある
jQuery
とpopper.js
の設定を追加してあげます。config/webpack/environment.jsconst { environment } = require('@rails/webpack') const webpack = require('webpack') environment.plugins.append('Provide', new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery', Popper: ['popper.js', 'default'] })) module.exports = environmentやばいですね。たったこれだけでBootstrapの準備が整いました。Bootstrapで用意されているあらゆるスタイルシートやjavascriptが利用可能になっちゃいました。
BootstrapがどんなことができるかはBootstrap公式のDocumentationを見るのが一番いいと思っているのですが、これだけの表現が上の設定でできるようになってしまったのです。Topページを作成する
いよいよ静的なページを作っていきます。
静的なページではModelのような動的なものはいらないのでMVCのVCがあればOKですね。
VC(ルーティングも!)はrails generate controller
コマンドで作成することができます。今回はstatic_pages
controllerでhome
actionを作ってみましょう。# rails generate controller static_pages home
rails generate controller NAME [action action]
の形式でコマンドを実行できます。actionは複数指定可能です。
慣習的にNAME
は複数形を用います。このコマンドだけですでに
http://localhost:3000/static_pages/home
へのRouting, Controller#Action, Viewが出来上がっているのでアクセスできるようになっていますね。
このコマンドで作成・更新されたファイルの中身をちょっとみていきましょう!
Routing
config/routes.rbRails.application.routes.draw do get 'static_pages/home' end
get 'static_pages/home'
の行が追加されてます。前回はresouces
メソッドを使ったルーティングの指定の仕方でしたが、このように一つ一つのルートを定義することもできるのです。
これだけで「static_pages/home
のパスにget
メソッドできたリクエストをstatic_pages
controllerのhome
actionにルーティングする」ことを定義しています。Controller
app/controllers/static_pages_controller.rbclass StaticPagesController < ApplicationController def home end end
home
アクションが定義されていますね。特段処理はないので、app/views/static_pages/home.html.erb
をレンダリングするのみです。View
app/views/static_pages/home.html.erb<h1>StaticPages#home</h1> <p>Find me in app/views/static_pages/home.html.erb</p>
app/views/static_pages/home.html.erb
ファイルが生成されています。
中身も先ほどhttp://localhost:3000/static_pages/home
と同じものが表示されていることがわかりますね。ルートパスをTopページにする
現状ルートパス(
http://localhost:3000
)にアクセスするとHello worldのページが表示されています。本当はこのURLにアクセスしたときにTopページを表示させたいのでルーティングの設定を更新していきます。config/routes.rbRails.application.routes.draw do root 'static_pages#home' endルートパスの設定の仕方は`root '[controller_name]#[action_name]'とするだけです!
試しに
http://localhost:3000/
にアクセスしてみてください。Topページが表示されるようになりましたね。
またhttp://localhost:3000/static_pages/home
にもう一度アクセスしてみましょう。get 'static_pages/home'
を削除してるので以下のようにそんなルートないよとエラーになります。
Bootstrapでページを装飾する
にしても味気ないページですよね。ということでBootstrapのCSSを使いながらいい感じのページに装飾していきましょう!
CSSはHTMLのスタイル(色とか大きさとか)をまとめた変数みたいなものです。HTMLタグ(<h1>とか<p>とか)にclass属性をつけることでそのスタイルが適用されます。SCSSはCSSを書きやすくしたものです(なので本質はCSS)。
<h1 class="hoge">Hello.</h1>.hoge { font-size: 32px; color: red; }これで32pxの赤文字で"Hello."が表示されるようになるってイメージですね。
Topページのコンテンツを装飾する
ではまず、
app/views/static_pages/home.html.erb
を更新していい感じのTopページを作っていきましょう。app/views/static_pages/home.html.erb<div class="jumbotron mb-0"> <div class="container text-center"> <h1>Welcome to Sample App.</h1> <h2>Twitterみたいなアプリです。</h2> <%= link_to "Sign up now!", "#", class: "btn btn-lg btn-primary mt-5" %> </div> </div>ここに出てくる
jumbotron
,container
,text-center
,btn
,btn-lg
,btn-primary
,mt-5
はすべてBootstrapのclassです。Bootstrapのclassの使い方はしっかりと公式のDocumantationがあるのでそちらをみてみましょう。実際に自分で何かを作るとなるとこういう公式ドキュメントと向き合うことが一番の近道だったりするのでここでは説明しないっす。1つだけ、ERBコードがありますね。
app/views/static_pages/home.html.erb<%= link_to "Sing up now!", "#", class: "btn btn-lg btn-primary mt-5" %>
link_to
はリンクを作るためのメソッドです。HTML的にいえば<a>
タグを作ってくれるということです。
link_to [表示文字], [リンク先], [options]
の構文になってまして、今回の例だと以下のような<a>
タグが出来上がります。<a href="#" class="btn btn-lg btn-primary mt-5">Sign up now!</a>リンク文字列やリンク先などに変数を指定でき(例えばルートパスはroot_pathが変数として割り当てられている)るのでERBファイルでリンクを作成する場合多用するコードなので覚えておきましょう。
リンク先として#を指定していますが、まだ遷移先のページを作成していないので仮置きしているだけです(#を指定しておくとリンクを押しても今いるページから遷移しないです。)編集ができたらトップページをリロードしてみましょう。以下のページになっていれば成功です!
ふへー。ぽくなってきましたね。
ただHeaderとかFooterとかも欲しくなってきました。
ヘッダーを装飾する
突然ですが、ブラウザでトップページのソースコードをみてみましょう。(右クリックで「ページのソースを表示する」を選択するとみれます。)
app/views/static_pages/home.html.erb
に全く書いた記憶がないもの、例えば<head>
タグとかがありますよね。Topページ<!DOCTYPE html> <html> <head> <title>App</title> <meta name="csrf-param" content="authenticity_token" /> <meta name="csrf-token" content="3702TRDf2wiVe1ErXV1NWoksR1sWw1+LO31miZuonos9K8zOmMwJ+VotF3ZXCPRP+g9IiKoZovoA8HpIjLjqmA==" /> <link rel="stylesheet" media="all" href="/assets/application.debug-9519f0a34796e622c941135a612890361ca8a44f05d715927aaa1575ce29c235.css" data-turbolinks-track="reload" /> <script src="/packs/js/application-923746675d9ea6d857bd.js" data-turbolinks-track="reload"></script> </head> <body> <div class="jumbotron"> <div class="container text-center"> <h1>Welcome to Sample App.</h1> <h2>Twitterみたいなアプリです。</h2> <a class="btn btn-lg btn-primary mt-5" href="#">Sign up now!</a> </div> </div> </body> </html>これはなんでしょう?
実はRailsアプリケーションではViewファイルの中でもLayoutと呼ばれるやつがいます。こいつはなにかというと、ページで共通な部分を表現してくれるものです。デフォルトで
app/views/layouts/application.html.erb
のレイアウトファイルが利用されています。ちょっと中を覗いてみましょう。app/views/layouts/application.html.erb<!DOCTYPE html> <html> <head> <title>App</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> </body> </html>ERBコードが入っているので少し表現は違いますが、Topページのソースコードと似た構文をしていることがわかります。実は最終的に表示されているHTMLは
app/views/static_pages/home.html.erb
がこのapp/views/layouts/application.html.erb
の<%= yield %>
に代入されたものです。少しだけ
app/views/layouts/application.html.erb
の中身をご紹介。
まず全体の構文ですが、HTMLの基本の構文が記述されていますね。<!DOCTYPE html> <html> <head> ... </head> <body> ... </body> </html>
<body>
の中のyeild
については上で話した通りで、actionのviewファイルの中身が代入されるようになっています。
<head>
の中はどうでしょうか?title
title
はブラウザのタブのところに表示される文字列です。今だとApp
と指定されているのでそれが表示されていますね。scrf_meta_tags
CSRF(Cross-Site Request Forgery)対策のための記述です。今回のTopページではあまり活躍しませんが、POSTリクエストを飛ばすページで活躍します。簡単にいえば、正しいユーザーからのリクエストなのかというリクエストの真正性(Authenticity)を検証するために必要なことを開発者が意識せずともRailsがカバーしてくれるようになるとのこと。
csp_meta_tag
CSP(Content Security Policy)に必要なタグを生成してくれるコードです。CSPはXSS(Cross Site Scripting)を防ぐためのもので、コンテンツの提供元や取得方法を制限する手法です。別途、制限を設定することで動作するようになります。ここでは紹介程度。
stylesheet_link_tag
stylesheetの読み込み。
app/assets/stylesheets/application.css[scss]
を読み込んでくれている。javascript_pack_tag
javascriptの読み込み。
app/javascript/packs/application.js
を読み込んでくれている。ってな具合です。
さて、長々と話してしまいましたが、本当に言いたかったことは『ヘッダーやフッターは各ページ個別のものではなく、サイトで共通のものであるはずなので、レイアウトファイルに記述するんだよ』ということです。
では、ヘッダーを
app/views/layouts/application.html.erb
に記述します!app/views/layouts/application.html.erb... <body> <header class="navbar navbar-dark navbar-expand bg-dark"> <div class="container"> <%= link_to "sample app", root_path, class: "navbar-brand" %> <ul class="navbar-nav"> <li class="nav-item"><%= link_to "Home", root_path, class: "nav-link" %></li> <li class="nav-item"><%= link_to "Sign in", "#", class: "nav-link" %></li> </ul> </div> </header> <%= yield %> </body> ...このあたりもBootstrapの公式ドキュメントを参考に記述してみました => Navbar · Bootstrap
Topページにアクセスしてみましょう。以下のようになっていれば成功です!
おー、どんどんぽくなってきましたね!フッターを装飾する
最後にフッターも付けちゃいましょう!今回はコピーライトを書いているくらいのフッターをば。
フッターは
<footer>
タグを使います。app/views/layouts/application.html.erb... <body> ... <%= yield %> <footer class="bg-dark"> <p class="text-center text-white py-2 mb-0">(c) Hoge Inc. All Rights Reserved.</p> </footer> </body> ...特別難しいところはありませんね。再度Topページにアクセスします。
おー、ぽい。ぽいのですが、ブラウザの下の方に余白ができているのが気になりますね...
表示するコンテンツがブラウザの縦サイズに合わない場合は、フッターは画面の最下部に表示されるようにしたい...ということで少しCSSをいじってみましょう。
app/assets/stylesheets/application.scss@import 'bootstrap/scss/bootstrap'; body { display: flex; flex-direction: column; min-height: 100vh; } footer { margin-top: auto; }本当はfooter用のファイルを作って
appliction.scss
で@import
する方が整理されるのでいいのですが、今回は分量も少ないのでひとまずapplication.scss
に記述します。これで何をしているかというと、まず
body
タグに対してdisplay: flex;
をあててます。これはFlexboxという要素をきれいに横並びや縦並びでレイアウトしてくれるレイアウトモジュールです。
flex-direction: column;
と定義しているので縦方向に要素を並べてくれます。
そして、min-height: 100vh;
を定義しているのでbody
タグで囲まれた要素は最低ブラウザいっぱいの高さを持つ要素に指定されたことになります。今、
body
タグの中にはheader
,<%= yeild %>の中のdiv
,footer
の3つの要素が同じレベルに存在しています。これを縦方向に並べていることになるんですね。
この時、Flexboxの親要素(今回だとbody
)をコンテナ、子要素(今回だとheader
,div
,footer
)をアイテムと呼びます。
footer
にはmargin-top: auto;
が定義されています。これは親要素に対して、この要素の上部に最大限のmargin(余白)を付与することを表していて、簡単に言うと親要素の一番下に配置するってことになります。
今、親要素のbody
は縦に最小で100vhの高さを持ちます。コンテンツが足りない場合はbody
は100vhの高さになるのでfooter
は100vhの一番下に位置します。コンテンツが100vh以上の場合はbody
もheader
,div
,footer
の3要素の高さの合計が高さになるので、footer
は自然な形でdiv
のすぐ下に配置されることになります。さてさて、ではTopページをリロードしてみてください!
とてもいい感じになりましたね!スマートフォンに対応する
PCだといい感じに表示されるのですが、スマートフォンだと実はとても見にくい状態になっています。ChromeのDeveloper toolsなどで確かめてみてください(Chrome DevTools での Device Mode によるモバイル端末のシミュレート)
BootstrapはもともとResponsive Design(ブラウザの横幅に合わせてCSSが変わる)に対応しているので、Viewport設定の1行を
head
タグ内に挿入するだけでいい感じのデザインになります。app/views/layouts/application.html.erb... <head> ... <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> ... </head> ...呪文みたいな感じで書いちゃうことが多いのですが、意味は「もう逃げない。HTMLのviewportをちゃんと理解する - Qiita」の記事が参考になりました。
スマホモードでリロードしてみましょう。
文字の大きさもいい感じになりましたね。Google Fontsでフォントを変える
んー。デザインはよくなってきたけどフォントがデフォルトっぽくて気になるなぁ...
フォントはこのアプリを使うユーザーの端末にフォントがインストールされていないと使えなかったりするのであんまり冒険できないところだったりします。アプリケーションの中でフォントを配布してもいいのですが、まぁ若干面倒ですね。
そこで便利なのがGoogle Fontsです。『Webフォント』と呼ばれますが、インターネット上ですでに公開されているため端末のインストールなしで利用でき、どの端末からでも同じフォントで表現ができるようになります。
app/assets/stylesheets/application.scss
でGoogle Fontsの中からNoto Sans JP
をインポートしてbody
のfont-family
に指定するだけなんですね簡単です。app/assets/stylesheets/application.scss@import 'bootstrap/scss/bootstrap'; // Google Fontsから"Noto Sans JP"をインポート @import url('https://fonts.googleapis.com/css?family=Noto+Sans+JP&display=swap'); body { // "Noto Sans JP"を全体のデフォルトフォントに指定 font-family: 'Noto Sans JP', sans-serif!important; display: flex; flex-direction: column; min-height: 100vh; } footer { margin-top: auto; }少し特別な書き方として、
font-family
のところで!important
と末尾に記述してます。
!important
はCSSの適用優先度を決めるための記述で、最優先で反映させるものに使います。つまり、他にfont-family
を記述したとしてもこいつが適用されるってことです。
Bootstrapでもfont-family
を定義してくれていたりするので、こっちを最優先にするために記述してます。Google Fontsのサイトでお好きなフォントを探してみて適用してみてください!日本語フォントの場合は、『Language』で『Japanese』を選択すれば日本語フォントありに絞られます。『+』で使用フォントを追加するとインポートの仕方とかも教えてくれるので気軽に使えます。もっと詳しくはこちらの記事から↓
【2019年版】Google Fontsの使い方:初心者向けに解説!まとめ
今回は、Railsの初期設定とBootstrapのインストール、Topページのデザインをやってみました。
静的なページではありますが、コーディングした内容が反映されてどんどん変わっていくのを実感する楽しみを感じてもらえたんじゃないかと思います。次回は今回触れていなかったModelが主役です。Modelの作成からModelに用意されているメソッドを使ってデータの作成や更新を遊んでみようと思います。
では、次回も乞うご期待!ここまでお読みいただきありがとうございました!
Reference
- Ruby on Rails チュートリアル:実例を使って Rails を学ぼう
- Railsタイムゾーンまとめ - Qiita
- rails-i18n/ja.yml at master · svenfuchs/rails-i18n
- もう迷わない!CSS Flexboxの使い方を徹底解説 | Web Design Trends
- 【2019年版】Google Fontsの使い方:初心者向けに解説!
P.S. 間違っているところ、抜けているところ、説明の仕方を変えるとよりわかりやすくなるところなどありましたら、優しくアドバイスいただけると助かります。
- 投稿日:2020-02-08T17:15:07+09:00
CentOS8にDockerをインストール。名前解決できなかったのが解消した。
はじめに
さっき書いた ESXi6.7にCentOS8を最小構成で構築 の作業後に、dockerを入れたけど、dnfでこけてしまった。
pingでIP直打ちは外に通るのに、名前解決ができない。が解決したので、記録として残します。
コンテナ起動時に--net=host
をやりたくなかったので情報をさがしてみました。解決方法だけ記載
ホスト側で、NAPTの設定したら動いた。
# firewall-cmd --add-masquerade --permanent # firewall-cmd --reload前提条件
最小構成でインストールしたからでしょうか?nftablesは起動しておらず、firewalldが動作し、裏でiptablesが動いている状態でした。
nftablesは停止している。
# systemctl status nftables ● nftables.service - Netfilter Tables Loaded: loaded (/usr/lib/systemd/system/nftables.service; disabled; vendor preset: disabled) Active: inactive (dead) Docs: man:nft(8)firewalldが動いている。
# systemctl status firewalld ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2020-02-08 16:28:47 JST; 27min ago Docs: man:firewalld(1) Main PID: 1182 (firewalld) Tasks: 2 (limit: 23585) Memory: 38.9M CGroup: /system.slice/firewalld.service mq1182 /usr/libexec/platform-python -s /usr/sbin/firewalld --nofork --nopidiptablesが動いている。
# iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy DROP) target prot opt source destination DOCKER-USER all -- anywhere anywhere DOCKER-ISOLATION-STAGE-1 all -- anywhere anywhere ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED DOCKER all -- anywhere anywhere ACCEPT all -- anywhere anywhere ACCEPT all -- anywhere anywhere Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain DOCKER (1 references) target prot opt source destination Chain DOCKER-ISOLATION-STAGE-1 (1 references) target prot opt source destination DOCKER-ISOLATION-STAGE-2 all -- anywhere anywhere RETURN all -- anywhere anywhere Chain DOCKER-ISOLATION-STAGE-2 (1 references) target prot opt source destination DROP all -- anywhere anywhere RETURN all -- anywhere anywhere Chain DOCKER-USER (1 references) target prot opt source destination RETURN all -- anywhere anywheredockerを使えるようにする
パッケージのインストール
インストール時のパッケージのバージョンではねられるので、
--nobest
をつけてインストールする。# dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # dnf install --nobest docker-ce docker-ce-cli containerd.ioサービス設定しておく
# systemctl enable docker # systemctl start dockerテストで
hello-world
を立ち上げてみる。
うまくいけば、下のように、Hello from Docker!
が表示される# docker run hello-world 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/CentOS8のイメージで起動してみる
systemctl
を動作させるために、/sbin/init
で走らせないとダメぽい。# docker pull centos:centos8 # docker run --privileged -it -d --name centos8_check centos:centos8 /sbin/init # docker exec -it centos8_check /bin/bash [root@fced0781866f /]#ログインできた。
トラブル発生
名前解決できない!
コンテナ内でepelパッケージのインストールしてみようとしたら、できない。
[root@fced0781866f /]# dnf install epel-release Failed to set locale, defaulting to C.UTF-8 CentOS-8 - AppStream 0.0 B/s | 0 B 00:05 Failed to download metadata for repo 'AppStream' Error: Failed to download metadata for repo 'AppStream'コンテナ→GooglePublicDNSはIP直打ちで到達できる。
[root@fced0781866f /]# ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=52 time=5.60 msコンテナのDNSはLAN内のサーバを参照している
[root@fced0781866f /]# cat /etc/resolv.conf # Generated by NetworkManager search prosper2.net nameserver 10.254.10.241コンテナ→DNSへのpingは通る
[root@fced0781866f /]# ping 10.254.10.241 PING 10.254.10.241 (10.254.10.241) 56(84) bytes of data. 64 bytes from 10.254.10.241: icmp_seq=1 ttl=127 time=0.467 msのに、名前解決できない
[root@fced0781866f /]# ping dns.google ping: dns.google: Name or service not knownなぜだ。。。
解消できた
ホスト側で、NAPTの設定したら動いた。
# firewall-cmd --add-masquerade --permanent # firewall-cmd --reloadちゃんと
dnf install epel-release
できた。# dnf install epel-release Failed to set locale, defaulting to C.UTF-8 CentOS-8 - AppStream 4.7 MB/s | 6.4 MB 00:01 CentOS-8 - Base 4.8 MB/s | 5.0 MB 00:01 CentOS-8 - Extras 6.2 kB/s | 2.1 kB 00:00 Dependencies resolved. =============================================================================================== Package Architecture Version Repository Size =============================================================================================== Installing: epel-release noarch 8-5.el8 extras 22 k Transaction Summary =============================================================================================== Install 1 Package Total download size: 22 k Installed size: 30 k Is this ok [y/N]: y Downloading Packages: epel-release-8-5.el8.noarch.rpm 915 kB/s | 22 kB 00:00 ----------------------------------------------------------------------------------------------- Total 36 kB/s | 22 kB 00:00 warning: /var/cache/dnf/extras-cbfb2f07b0021b7e/packages/epel-release-8-5.el8.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY CentOS-8 - Extras 1.6 MB/s | 1.6 kB 00:00 Importing GPG key 0x8483C65D: Userid : "CentOS (CentOS Official Signing Key) <security@centos.org>" Fingerprint: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D From : /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial Is this ok [y/N]: y Key imported successfully Running transaction check Transaction check succeeded. Running transaction test Transaction test succeeded. Running transaction Preparing : 1/1 Installing : epel-release-8-5.el8.noarch 1/1 Running scriptlet: epel-release-8-5.el8.noarch 1/1 Verifying : epel-release-8-5.el8.noarch 1/1 Installed: epel-release-8-5.el8.noarch Complete!追記
インストール時に
--nobest
でとりあえずは大丈夫だったけど、依存関係のエラーが出続けてしまっていた。# dnf update メタデータの期限切れの最終確認: 0:53:51 時間前の 2020年02月08日 16時38分36秒 に実施しました。 エラー: 問題: 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 update candidate for package docker-ce-3:18.09.1-3.el7.x86_64 - 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' を追加して、最適候補のパッケージのみを使用しないでください)これは嫌なので、無理やりRPMを入れてしまおう。まず、どこにあるか調べる。
# grep stable /etc/yum.repos.d/docker-ce.repo [docker-ce-stable] baseurl=https://download.docker.com/linux/centos/7/$basearch/stableそうか、そもそもCentOS7がターゲットなのか。。。
ここから拾ってこよう。# dnf update https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.10-3.2.el7.x86_64.rpm メタデータの期限切れの最終確認: 1:00:47 時間前の 2020年02月08日 16時38分36秒 に実施しました。 containerd.io-1.2.10-3.2.el7.x86_64.rpm 7.5 MB/s | 23 MB 00:03 依存関係が解決しました。 ======================================================================================================================================================================== パッケージ アーキテクチャー バージョン リポジトリー サイズ ======================================================================================================================================================================== アップグレード: containerd.io x86_64 1.2.10-3.2.el7 @commandline 23 M トランザクションの概要 ======================================================================================================================================================================== アップグレード 1 パッケージ 合計サイズ: 23 M これでよろしいですか? [y/N]: y パッケージのダウンロード: トランザクションの確認を実行中 トランザクションの確認に成功しました。 トランザクションのテストを実行中 トランザクションのテストに成功しました。 トランザクションを実行中 準備 : 1/1 scriptletの実行中: containerd.io-1.2.10-3.2.el7.x86_64 1/1 アップグレード中 : containerd.io-1.2.10-3.2.el7.x86_64 1/2 scriptletの実行中: containerd.io-1.2.10-3.2.el7.x86_64 1/2 scriptletの実行中: containerd.io-1.2.0-3.el7.x86_64 2/2 整理 : containerd.io-1.2.0-3.el7.x86_64 2/2 scriptletの実行中: containerd.io-1.2.0-3.el7.x86_64 2/2 検証 : containerd.io-1.2.10-3.2.el7.x86_64 1/2 検証 : containerd.io-1.2.0-3.el7.x86_64 2/2 アップグレード済み: containerd.io-1.2.10-3.2.el7.x86_64 完了しました!よしよし、もっかいupdateしよ。
# dnf update メタデータの期限切れの最終確認: 1:01:08 時間前の 2020年02月08日 16時38分36秒 に実施しました。 依存関係が解決しました。 ======================================================================================================================================================================== パッケージ アーキテクチャー バージョン リポジトリー サイズ ======================================================================================================================================================================== アップグレード: docker-ce x86_64 3:19.03.5-3.el7 docker-ce-stable 24 M トランザクションの概要 ======================================================================================================================================================================== アップグレード 1 パッケージ ダウンロードサイズの合計: 24 M これでよろしいですか? [y/N]: y パッケージのダウンロード: docker-ce-19.03.5-3.el7.x86_64.rpm 7.2 MB/s | 24 MB 00:03 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 合計 7.2 MB/s | 24 MB 00:03 トランザクションの確認を実行中 トランザクションの確認に成功しました。 トランザクションのテストを実行中 トランザクションのテストに成功しました。 トランザクションを実行中 準備 : 1/1 scriptletの実行中: docker-ce-3:19.03.5-3.el7.x86_64 1/1 アップグレード中 : docker-ce-3:19.03.5-3.el7.x86_64 1/2 scriptletの実行中: docker-ce-3:19.03.5-3.el7.x86_64 1/2 scriptletの実行中: docker-ce-3:18.09.1-3.el7.x86_64 2/2 /usr/bin/dockerd は dockerd の為の互換用として設定されていません。 整理 : docker-ce-3:18.09.1-3.el7.x86_64 2/2 scriptletの実行中: docker-ce-3:18.09.1-3.el7.x86_64 2/2 検証 : docker-ce-3:19.03.5-3.el7.x86_64 1/2 検証 : docker-ce-3:18.09.1-3.el7.x86_64 2/2 アップグレード済み: docker-ce-3:19.03.5-3.el7.x86_64 完了しました!うん、大丈夫そう。
# dnf update メタデータの期限切れの最終確認: 1:01:38 時間前の 2020年02月08日 16時38分36秒 に実施しました。 依存関係が解決しました。 行うべきことはありません。 完了しました!よかった。
出典
- 投稿日:2020-02-08T15:50:56+09:00
雑に知ってしまったDockerを雑に知り直す
かわいい。Moby Dockという名前だそうです。
(くん付けかちゃん付けかで悩んで性別調べたけど出てこなかったので、ご存知の方いたらこっそり教えて下さい)TL;DR
- Dockerの存在は知っていて、コンテナ起動の方法なんかも知っている
- 自分でイメージ作成したことが無く、ちゃんとしたデバッグの手法とか知らないので改めて一から学ぶ
- k8sとかもそのうちやる
Dockerとは
星の数ほど書かれた見出しではあるものの、単語が多すぎて???ってよくなります。
解説記事眺めていて登場頻度が高めだなと感じた単語だけピックアップ。(適宜更新予定)
- 仮想化
ホスト型/ハイパーバイザ型/コンテナ型などの方式があり、Dockerはコンテナ型。他の方式との違いについては実際に触っていないのでハッキリとは言えず。解説記事を鵜呑みにするなら
- 構成のコード化。コードなので共有するためのファイルが軽い
- 処理/起動が早い
- プロセス:コンテナの比率は基本的に1:1
DBサーバとAPIサーバが必要なアプリケーションを構成する場合、他の方式だと一つの仮想環境にまとめることが多いが、コンテナ型の場合は1つのコンテナに対して1つのプロセス。よってコンテナを2つ立ち上げる。サービスの規模次第とも思うので例外はありそうだけど、これがベストプラクティスらしい。- ホストマシン
Dockerをインストールしたマシン。今この記事を書いているMacbookのこと。- Dockerエンジン
Dockerのコア。Dockerそのものっていう認識。- コンテナ
超頻出。センター英語で言うとas long asぐらい頻出。うまく言語化するのが難しいけどプロセスの実行環境みたいな。ホストマシンからは分離された独立した環境。- Dockerイメージ
これも超頻出。コンテナの設計図、なんて解説されたりもしているけど、調べてくうちに設計図兼ファイル群みたいなイメージなのかなと感じた。レイヤ構造になっていて理解するにはLinuxの知識がもっと必要だと感じたので要勉強。- Docker Hub
大量のDockerイメージが保存されたクラウド。
プログラミング言語の実行環境や、DBサーバWebサーバのイメージなどが置いてあり、ここからイメージを引っ張ってくればあっというまに環境ができあがる。インストール
※今回もmacでやってます
https://hub.docker.com/ からdmgファイル落としてきていつも通りのムーブでインストールしましょう。
前は特にアカウントとか要らなかった気がするけど、今は会員登録してダウンロードするらしい。
ちゃんと探せば会員登録しなくても落とせるリンクありそう。brewをインストールしてあるなら以下でいけるはず
$ brew install docker $ brew cask install docker使ってみる
今回はnginxサーバ立ち上げてみました。
$ docker run [Dockerイメージ名] -d バックグラウンド起動 -p ポートフォワード設定 --name コンテナに名前をつける $ docker run -d -p 80:80 --name webserver nginx Unable to find image 'nginx:latest' locally # nginxっていう名前のイメージをまずローカルで探してから、Docker Hubを見に行く latest: Pulling from library/nginx bc51dd8edc1b: Pull complete 66ba67045f57: Pull complete bf317aa10aa5: Pull complete Digest: sha256:ad5552c786f128e389a0263104ae39f3d3c7895579d45ae716f528185b36bc6f Status: Downloaded newer image for nginx:latest 0d5655a34ba94e4cecad342f78e943830ea452f196ce5017464547266d6658b8http://localhost:80 へアクセス
お手軽すぎてYABAI
- 立ち上げたコンテナ情報やイメージ情報確認
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 2073e0bcb60e 5 days ago 127MB $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0d5655a34ba9 nginx "nginx -g 'daemon of…" 8 minutes ago Up 8 minutes 0.0.0.0:80->80/tcp webserver
- コンテナへ接続
$ docker exec -it webserver(コンテナ名) /bin/bash root@0d5655a34ba9:/# hostname 0d5655a34ba9 # ちゃんとnginxの設定ファイルもある root@0d5655a34ba9:/# cat /etc/nginx/nginx.conf user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; }
- コンテナ停止
$ docker stop webserver webserver $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # コンテナ停止しただけなので、イメージは残ってる $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 2073e0bcb60e 5 days ago 127MBうんうん。
おわり
nginxはユーザ設定やパフォーマンスを少しいじったことがあるだけでインストールすらしたことありません。よくわからんけどなんか動いてる、っていうのはまさにこのこと。楽しいけど良し悪しあるなぁというのが本音です。(せっかくなのでnginxの勉強もします)
nginxコンテナを起動したわけですが、ここからの道のりはまだまだ長く。。
どうやってこの環境にアプリケーション持ち込むの?とか、
自分の好きな設定をいれたDockerイメージを作成したりとか、
コンテナはそれぞれが隔離された環境なのでコンテナ同士が通信できるようにしたりとか。
知らないといけないことは山積みなので定期的にインプット/アウトプットしていきます。今回の学び
テザリングでのpullのし過ぎには気をつけましょう。
- 投稿日:2020-02-08T15:50:56+09:00
雑に知ってしまったDockerを知り直す
かわいい。Moby Dockという名前だそうです。
(くん付けかちゃん付けかで悩んで性別調べたけど出てこなかったので、ご存知の方いたらこっそり教えて下さい)TL;DR
- Dockerの存在は知っていて、コンテナ起動の方法なんかも知っている
- 自分でイメージ作成したことが無く、ちゃんとしたデバッグの手法とか知らないので改めて一から学ぶ
- k8sとかもそのうちやる
Dockerとは
星の数ほど書かれた見出しではあるものの、単語が多すぎて???ってよくなります。
解説記事眺めていて登場頻度が高めだなと感じた単語だけピックアップ。(適宜更新予定)
- 仮想化
ホスト型/ハイパーバイザ型/コンテナ型などの方式があり、Dockerはコンテナ型。他の方式との違いについては実際に触っていないのでハッキリとは言えず。解説記事を鵜呑みにするなら
- 構成のコード化。コードなので共有するためのファイルが軽い
- 処理/起動が早い
- プロセス:コンテナの比率は基本的に1:1
DBサーバとAPIサーバが必要なアプリケーションを構成する場合、他の方式だと一つの仮想環境にまとめることが多いが、コンテナ型の場合は1つのコンテナに対して1つのプロセス。よってコンテナを2つ立ち上げる。サービスの規模次第とも思うので例外はありそうだけど、これがベストプラクティスらしい。- ホストマシン
Dockerをインストールしたマシン。今この記事を書いているMacbookのこと。- Dockerエンジン
Dockerのコア。Dockerそのものっていう認識。- コンテナ
超頻出。センター英語で言うとas long asぐらい頻出。うまく言語化するのが難しいけどプロセスの実行環境みたいな。ホストマシンからは分離された独立した環境。- Dockerイメージ
これも超頻出。コンテナの設計図、なんて解説されたりもしているけど、調べてくうちに設計図兼ファイル群みたいなイメージなのかなと感じた。レイヤ構造になっていて理解するにはLinuxの知識がもっと必要だと感じたので要勉強。- Docker Hub
大量のDockerイメージが保存されたクラウド。
プログラミング言語の実行環境や、DBサーバWebサーバのイメージなどが置いてあり、ここからイメージを引っ張ってくればあっというまに環境ができあがる。インストール
※今回もmacでやってます
https://hub.docker.com/ からdmgファイル落としてきていつも通りのムーブでインストールしましょう。
前は特にアカウントとか要らなかった気がするけど、今は会員登録してダウンロードするらしい。
ちゃんと探せば会員登録しなくても落とせるリンクありそう。brewをインストールしてあるなら以下でいけるはず
$ brew install docker $ brew cask install docker使ってみる
今回はnginxサーバ立ち上げてみました。
$ docker run [Dockerイメージ名] -d バックグラウンド起動 -p ポートフォワード設定 --name コンテナに名前をつける $ docker run -d -p 80:80 --name webserver nginx Unable to find image 'nginx:latest' locally # nginxっていう名前のイメージをまずローカルで探してから、Docker Hubを見に行く latest: Pulling from library/nginx bc51dd8edc1b: Pull complete 66ba67045f57: Pull complete bf317aa10aa5: Pull complete Digest: sha256:ad5552c786f128e389a0263104ae39f3d3c7895579d45ae716f528185b36bc6f Status: Downloaded newer image for nginx:latest 0d5655a34ba94e4cecad342f78e943830ea452f196ce5017464547266d6658b8http://localhost:80 へアクセス
お手軽すぎてYABAI
- 立ち上げたコンテナ情報やイメージ情報確認
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 2073e0bcb60e 5 days ago 127MB $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0d5655a34ba9 nginx "nginx -g 'daemon of…" 8 minutes ago Up 8 minutes 0.0.0.0:80->80/tcp webserver
- コンテナへ接続
$ docker exec -it webserver(コンテナ名) /bin/bash root@0d5655a34ba9:/# hostname 0d5655a34ba9 # ちゃんとnginxの設定ファイルもある root@0d5655a34ba9:/# cat /etc/nginx/nginx.conf user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; }
- コンテナ停止
$ docker stop webserver webserver $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # コンテナ停止しただけなので、イメージは残ってる $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 2073e0bcb60e 5 days ago 127MBうんうん。
おわり
nginxはユーザ設定やパフォーマンスを少しいじったことがあるだけでインストールすらしたことありません。よくわからんけどなんか動いてる、っていうのはまさにこのこと。楽しいけど良し悪しあるなぁというのが本音です。(せっかくなのでnginxの勉強もします)
nginxコンテナを起動したわけですが、ここからの道のりはまだまだ長く。。
どうやってこの環境にアプリケーション持ち込むの?とか、
自分の好きな設定をいれたDockerイメージを作成したりとか、
コンテナはそれぞれが隔離された環境なのでコンテナ同士が通信できるようにしたりとか。
知らないといけないことは山積みなので定期的にインプット/アウトプットしていきます。今回の学び
テザリングでのpullのし過ぎには気をつけましょう。
- 投稿日:2020-02-08T15:40:54+09:00
SpringBoot 2.3.0 M1から入ったBuild Docker images with Cloud Native Buildpacksを試す
きっかけ
SpringBoot 2.3.0 M1がリリースされました。
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3.0-M1-Release-Notes
いろいろな改善や、不要機能の削除などがされていますが、リリースノートを見ていて気になった、Build Docker images with Cloud Native Buildpacksを試してみたいと思います。
リリースノートには、以下記載がありました。
Support for building Docker images using Cloud Native Buildpacks has been added to the Maven and Gradle plugins via the spring-boot:build-image goal and the bootBuildImage task.
MavenかGradleプラグインでDockerイメージが作れるようになるようです。
早速試したいと思い、その活動のまとめとなります。How to Get Started
前回と同じ設定で
Spring Initializr でアプリ雛形を作ります。
作成後に、環境情報を取得したかったので、SpringBoot Actuatorも有効にしておきます。早速DockerImageを作ります。イメージを作成する環境ではDockerDeamonを起動しておく必要があるので、その点は注意してください。
これまでSpringBootアプリケーションをDockerImageビルドする場合は以下のステップを踏んでました。
1.mvn package
でアプリのJarファイルを作成
2. どのようなDockerImageを作るのかをDockerfileに記載
3. docker buildコマンドでイメージを作成
- Dockerfileの設定例
FROM openjdk:8-jdk-alpine ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} app.jar ENTRYPOINT ["java","-jar","/app.jar"]Build Docker images with Cloud Native Buildpacksでは、上記手順を踏まずに1ステップでDockerImageまで作ることができます。
Mavenの場合は、mvn spring-boot:build-image
、Gradleの場合はgradle bootBuildImage
を叩くだけです。Cloud Native Buildpacksの機能で、ソースの中身を読み取ってDockerfileに設定が必要な内容を補完してくれます。$ mvn spring-boot:build-image [INFO] Scanning for projects... [INFO] [INFO] --------------------------< com.example:demo >-------------------------- [INFO] Building demo 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] >>> spring-boot-maven-plugin:2.3.0.M1:build-image (default-cli) > package @ demo >>> [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ demo --- [INFO] Nothing to compile - all classes are up to date 中略 [INFO] > Running builder [INFO] [builder] [INFO] [builder] Cloud Foundry OpenJDK Buildpack v1.0.80 [INFO] [builder] OpenJDK JRE 11.0.5: Reusing cached layer [INFO] [builder] [INFO] [builder] Cloud Foundry JVM Application Buildpack v1.0.113 [INFO] [builder] Executable JAR: Reusing cached layer [INFO] [builder] Process types: [INFO] [builder] executable-jar: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher [INFO] [builder] task: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher [INFO] [builder] web: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher [INFO] [builder] [INFO] [builder] Cloud Foundry Spring Boot Buildpack v1.0.157 [INFO] [builder] Spring Boot 2.3.0.M1: Reusing cached layer [INFO] [builder] Process types: [INFO] [builder] spring-boot: java -cp $CLASSPATH $JAVA_OPTS com.example.demo.DemoApplication [INFO] [builder] task: java -cp $CLASSPATH $JAVA_OPTS com.example.demo.DemoApplication [INFO] [builder] web: java -cp $CLASSPATH $JAVA_OPTS com.example.demo.DemoApplication [INFO] [builder] [INFO] [builder] Cloud Foundry Spring Auto-reconfiguration Buildpack v1.0.159 [INFO] [builder] Spring Auto-reconfiguration 2.11.0: Reusing cached layer [INFO] [INFO] > Running exporter [INFO] [exporter] Reusing layer 'app' [INFO] [exporter] Reusing layer 'config' [INFO] [exporter] Reusing layer 'launcher' [INFO] [exporter] Reusing layer 'org.cloudfoundry.openjdk:openjdk-jre' [INFO] [exporter] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar' [INFO] [exporter] Reusing layer 'org.cloudfoundry.springboot:spring-boot' [INFO] [exporter] Reusing layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration' [INFO] [exporter] *** Images (89a7e99f9c15): [INFO] [exporter] docker.io/library/demo:0.0.1-SNAPSHOT [INFO] [INFO] > Running cacher [INFO] [cacher] Reusing layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b' [INFO] [cacher] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar' [INFO] [cacher] Reusing layer 'org.cloudfoundry.springboot:spring-boot' [INFO] [cacher] Reusing layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150' [INFO] [INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT' [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 01:01 min [INFO] Finished at: 2020-02-08T15:30:43+09:00 [INFO] ------------------------------------------------------------------------初回はベースイメージのダウンロードとかで時間がかかりますが、2回目以上は上記の時間ぐらいでできます。
さて、ほんとにDockerImageができているのか、確認してみましょう。
docker images REPOSITORY TAG IMAGE ID CREATED SIZE demo 0.0.1-SNAPSHOT 89a7e99f9c15 About a minute ago 226MBちゃんといますね。起動は通常のDockerImageと同じです。ここでは
docker run -it -p8080:8080 demo:0.0.1-SNAPSHOT
で起動させます。docker run -it -p8080:8080 demo:0.0.1-SNAPSHOT . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.0.M1) 2020-02-08 06:33:43.540 WARN 1 --- [ main] pertySourceApplicationContextInitializer : Skipping 'cloud' property source addition because not in a cloud 2020-02-08 06:33:43.570 WARN 1 --- [ main] nfigurationApplicationContextInitializer : Skipping reconfiguration because not in a cloud 2020-02-08 06:33:43.635 INFO 1 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on 40fbed8bc770 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace) 2020-02-08 06:33:43.636 INFO 1 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default 2020-02-08 06:33:48.387 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-02-08 06:33:48.456 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-02-08 06:33:48.466 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.30] 2020-02-08 06:33:48.738 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-02-08 06:33:48.740 INFO 1 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 4841 ms 2020-02-08 06:33:50.208 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-02-08 06:33:50.900 INFO 1 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 14 endpoint(s) beneath base path '/actuator' 2020-02-08 06:33:51.122 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-02-08 06:33:51.142 INFO 1 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 9.779 seconds (JVM running for 12.428)無事、起動できています。前回アプリを使っているので、Actuatorも有効のままです。envの情報を取得してみましょう。
curl localhost:8080/actuator/env | jq % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 8753 0 8753 0 0 10130 0 --:--:-- --:--:-- --:--:-- 10130 { "activeProfiles": [], "propertySources": [ { "name": "server.ports", "properties": { "local.server.port": { "value": 8080 } } }, { "name": "servletContextInitParams", "properties": {} }, { "name": "systemProperties", "properties": { "awt.toolkit": { "value": "sun.awt.X11.XToolkit" }, "java.specification.version": { "value": "11" }, "sun.cpu.isalist": { "value": "" }, "sun.jnu.encoding": { "value": "ANSI_X3.4-1968" }, "java.class.path": { "value": "/layers/org.cloudfoundry.springautoreconfiguration/auto-reconfiguration/java-buildpack-auto-reconfiguration-2.11.0.RELEASE.jar:/workspace/BOOT-INF/classes:/workspace/BOOT-INF/lib/HdrHistogram-2.1.11.jar:/workspace/BOOT-INF/lib/LatencyUtils-2.0.3.jar:/workspace/BOOT-INF/lib/jackson-annotations-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-core-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-databind-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-datatype-jdk8-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-datatype-jsr310-2.10.1.jar:/workspace/BOOT-INF/lib/jackson-module-parameter-names-2.10.1.jar:/workspace/BOOT-INF/lib/jakarta.annotation-api-1.3.5.jar:/workspace/BOOT-INF/lib/jakarta.el-3.0.3.jar:/workspace/BOOT-INF/lib/jul-to-slf4j-1.7.29.jar:/workspace/BOOT-INF/lib/log4j-api-2.12.1.jar:/workspace/BOOT-INF/lib/log4j-to-slf4j-2.12.1.jar:/workspace/BOOT-INF/lib/logback-classic-1.2.3.jar:/workspace/BOOT-INF/lib/logback-core-1.2.3.jar:/workspace/BOOT-INF/lib/micrometer-core-1.3.3.jar:/workspace/BOOT-INF/lib/slf4j-api-1.7.29.jar:/workspace/BOOT-INF/lib/snakeyaml-1.25.jar:/workspace/BOOT-INF/lib/spring-aop-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-beans-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-boot-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-actuator-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-actuator-autoconfigure-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-autoconfigure-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-actuator-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-json-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-logging-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-tomcat-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-boot-starter-web-2.3.0.M1.jar:/workspace/BOOT-INF/lib/spring-context-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-core-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-expression-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-jcl-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-web-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/spring-webmvc-5.2.3.RELEASE.jar:/workspace/BOOT-INF/lib/tomcat-embed-core-9.0.30.jar:/workspace/BOOT-INF/lib/tomcat-embed-websocket-9.0.30.jar:/workspace" }, "java.vm.vendor": { "value": "AdoptOpenJDK" }, "sun.arch.data.model": { "value": "64" }, "java.vendor.url": { "value": "https://adoptopenjdk.net/" }, "catalina.useNaming": { "value": "false" }, "user.timezone": { "value": "GMT" }, "os.name": { "value": "Linux" }, "java.vm.specification.version": { "value": "11" }, "sun.java.launcher": { "value": "SUN_STANDARD" }, "user.country": { "value": "US" }, "sun.boot.library.path": { "value": "/layers/org.cloudfoundry.openjdk/openjdk-jre/lib" }, "sun.java.command": { "value": "******" }, "jdk.debug": { "value": "release" }, "sun.cpu.endian": { "value": "little" }, "user.home": { "value": "/home/cnb" }, "user.language": { "value": "en" }, "java.specification.vendor": { "value": "Oracle Corporation" }, "java.version.date": { "value": "2019-10-15" }, "java.home": { "value": "/layers/org.cloudfoundry.openjdk/openjdk-jre" }, "file.separator": { "value": "/" }, "java.vm.compressedOopsMode": { "value": "32-bit" }, "line.separator": { "value": "\n" }, "java.specification.name": { "value": "Java Platform API Specification" }, "java.vm.specification.vendor": { "value": "Oracle Corporation" }, "java.awt.graphicsenv": { "value": "sun.awt.X11GraphicsEnvironment" }, "java.awt.headless": { "value": "true" }, "sun.management.compiler": { "value": "HotSpot 64-Bit Tiered Compilers" }, "java.runtime.version": { "value": "11.0.5+10" }, "user.name": { "value": "cnb" }, "path.separator": { "value": ":" }, "os.version": { "value": "4.9.184-linuxkit" }, "java.runtime.name": { "value": "OpenJDK Runtime Environment" }, "file.encoding": { "value": "ANSI_X3.4-1968" }, "spring.beaninfo.ignore": { "value": "true" }, "java.vm.name": { "value": "OpenJDK 64-Bit Server VM" }, "java.vendor.version": { "value": "AdoptOpenJDK" }, "java.vendor.url.bug": { "value": "https://github.com/AdoptOpenJDK/openjdk-build/issues" }, "java.io.tmpdir": { "value": "/tmp" }, "catalina.home": { "value": "/tmp/tomcat.9057283283640867778.8080" }, "java.version": { "value": "11.0.5" }, "user.dir": { "value": "/workspace" }, "os.arch": { "value": "amd64" }, "java.vm.specification.name": { "value": "Java Virtual Machine Specification" }, "PID": { "value": "1" }, "java.awt.printerjob": { "value": "sun.print.PSPrinterJob" }, "sun.os.patch.level": { "value": "unknown" }, "catalina.base": { "value": "/tmp/tomcat.9057283283640867778.8080" }, "java.library.path": { "value": "/layers/org.cloudfoundry.openjdk/openjdk-jre/lib:/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib" }, "java.vendor": { "value": "AdoptOpenJDK" }, "java.vm.info": { "value": "mixed mode" }, "java.vm.version": { "value": "11.0.5+10" }, "sun.io.unicode.encoding": { "value": "UnicodeLittle" }, "java.class.version": { "value": "55.0" } } 後略Javaの実装はAdoptOpenJDKの11が使われていますね。OSはLinuxのようです。
まとめ
Dockerfileを書かなくてもよいので、Dockerの知識がなくても簡単にDockerImageを作成できました。仕様や細かい動きを確認しないと本番へすぐ投入とはいかなそうですが、気軽にDockerImage作成できることは、メリットとなるのではないでしょうか?
使ったソースコードは以下に配置しておきました。
ご参考です。
- 投稿日:2020-02-08T15:27:11+09:00
DockerでPythonのWebアプリケーションをnginx + gunicorn で起動する
構成
- Webサーバー
- nginx
- WSGIサーバー(APサーバー)
- Gunicorn
- Webアプリケーションフレームワーク
- Django
- ここではWSGIを使用するので、WSGIに準拠していれば他のフレームワークでも良い
- この記事ではDjango固有の設定は発生しない
- WebサーバーとWSGIサーバーはDockerコンテナで稼働させる
- WebサーバーとWSGIサーバーの通信にはUNIXドメインソケットを使用する
用語の整理
WSGIサーバーとは
- WSGIとはWeb Server Gateway Interfaceのことで、WebサーバーとPythonのAPサーバー間通信のプロトコルのこと
- DjangoやFlask、Bottleなどのフレームワークもこのプロトコルに準拠している
- 上記のWSGIに則ったAPサーバーをWSGIサーバーと呼び、Gunicornはその一種
- gunicorn以外のWSGIサーバーにはuWSGIがある
UNIXドメインソケットとは
- ファイルシステムのパスを通して通信相手を探す通信方法
- そのパスにファイルが作成され、それぞれのプロセスがそのファイルにアクセスする
- 単にファイルを共有しているだけに思えるが、作成されるファイルはソケットファイルと呼ばれる特殊なファイルであり実態はない
- あくまで通信のインターフェース
構築
Gunicorn
- まずはWSGIサーバーを単体で稼働させてみる
プロジェクト作成
- Djangoをインストールする
$ pip install Django==3.0.2
- 作業環境でプロジェクトを作成する
$ django-admin.py startproject django_project .
- ここではdjango_projectという名前でプロジェクトを作成
- treeコマンドで確認すると以下のようになる
$ tree . ├── django_project │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.pyGunicornコンテナ起動
- Dockerfileを作成
FROM python:3.8.0-alpine WORKDIR /usr/src/app ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 RUN pip install --upgrade pip COPY ./requirements.txt /usr/src/app/requirements.txt RUN pip install -r requirements.txt
- requirements.txt は以下の通り
requirements.txtDjango==3.0.2 gunicorn==20.0.4
- ビルドする
$ docker build -t gunicorn:tmp .
- docker-compose.yamlの記載は以下の通り
- 後でnginxの情報も追記する
version: '3.7' services: gunicorn: image: gunicorn:tmp container_name: gunicorn command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/usr/src/app/ ports: - 8000:8000
python manage.py runserver 0.0.0.0:8000
コマンドでテスト用簡易サーバーが起動される- ここでは稼働確認のため8000番のポートをフォワーディングしている
$ docker-compose up -d
で起動してlocalhost:8000にアクセスしてDjangoの画面が表示されればOKNginxでUNIXドメインソケット使用する設定
- 公式のDockerイメージを使用するが、UNIXドメインソケットの設定を記載したconfファイルを作成し起動時にマウントさせる
- gunicorn.confという名前で以下の内容を記載
gunicorn.confupstream gunicorn-django { server unix:///var/run/gunicorn/gunicorn.sock; } server { listen 80; server_name localhost; location / { try_files $uri @gunicorn; } location @gunicorn { proxy_pass http://gunicorn-django; } }
upstream gunicorn-django{…}
の内容がUNIXドメインソケットの設定- 記載したパスのソケットファイルを介することでgunicornと通信を行う
- つまりgunicorn側からもこのソケットファイルを呼び出す設定が必要になる
- あとはlocationのproxy_passでupstreamで指定したgunicorn-djangoを指定すればよい
- Nginxのdocker-compose.yamlの記載は以下の通り
version: '3.7' services: nginx: image: nginx:1.17.7 container_name: nginx ports: - "80:80" volumes: - ./gunicorn.conf:/etc/nginx/conf.d/default.conf
- Nginx内に
/etc/nginx/conf.d/default.conf
という名前でマウントする- Nginxは/etc/nginx/nginx.confを起動時に読み取り、そのファイル内で
include /etc/nginx/conf.d/*.conf;
という記載がされているため、/etc/nginx/conf.d
配下に自分で作成したconfファイルをマウントしておけば起動時に一緒に読み込んでくれるGunicornでUNIXドメインソケット使用する設定
- 先ほどローカルで起動させた状態から多少変更を加える
コンテナの起動コマンド
WSGIの設定
- GunicornがNginxと通信を行えるよう、以下のようなgunicornコマンドを叩く必要がある
gunicorn django_project.wsgi
- これは今回django_projectというプロジェクトを作成したときに構築されるdjango_project配下にあるwsgi.pyを読み込む
- ローカルで起動させるときはmanage.pyを起動させたが、WSGIで通信させるときはこのコマンドが必要になる
UNIXドメインソケットの設定
- UNIXドメインソケットで通信させるため、
--bind
で起動時ソケットファイルのパスを指定するgunicorn django_project.wsgi --bind=unix:/var/run/gunicorn/gunicorn.sock
- これによりgunicornへのUNIXドメインソケット通信が可能になる
Doickerfile修正
- 上記の内容を基に、DockerfileのCMDを変更
DockerfileFROM python:3.8.0-alpine WORKDIR /usr/src/app ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 RUN pip install --upgrade pip COPY ./requirements.txt /usr/src/app/requirements.txt RUN pip install -r requirements.txt RUN mkdir -p /var/run/gunicorn CMD ["gunicorn", "django_project.wsgi", "--bind=unix:/var/run/gunicorn/gunicorn.sock"]
- 再度ビルドしておく
$ docker build -t gunicorn:latest .Djangoプロジェクトへアクセスできるホストを指定
- django_project配下に作成されるsetting.py内の
ALLOWED_HOSTS=[]
に指定する- 本来なら制限するべきだが、ここでは全てのホストからのアクセスを許可するため
ALLOWED_HOSTS=[*]
にしておく- このファイルはwsgi.pyから呼び出されている
UNIXドメインソケット通信でマウントするボリュームを作成
- Nginx、Gunicornでソケットファイルのパスを指定したので、ソケットファイルのボリュームを作成する必要がある
- 今回はDockerで起動させるので、DockerのVolumeを起動時に作成し、2つのコンテナからそのVolumeにマウントを行う
- 最終的なdocker-compose.yamlは以下の通り
docker-compose.yamlversion: '3.7' services: gunicorn: image: gunicorn:latest container_name: gunicorn volumes: - .:/usr/src/app/ - gunicorn:/var/run/gunicorn nginx: image: nginx:1.17.7 container_name: nginx depends_on: - gunicorn ports: - "80:80" volumes: - ./gunicorn.conf:/etc/nginx/conf.d/default.conf - gunicorn:/var/run/gunicorn volumes: gunicorn: driver: local
- gunicornというVolumeを作成し、それぞれのコンテナにマウントする(今回はどちらのコンテナでも
/var/run/gunicorn
を指定している)稼働
- 以下のコマンドで起動
$ docker-compose up -d Starting gunicorn ... done Starting nginx ... done
- 起動後に
localhost
にアクセスしてみる
- 画面が表示されればOK
- 最初にGunicornを単体で稼働させたときと表示されている画面は同じだが、今回はnginxを経由して表示されている
ソースコード
- 今回作成したファイル一式はこちら
参考
- 投稿日:2020-02-08T15:27:11+09:00
DockerでPythonのWebアプリケーションをNginx + Gunicorn で起動する
構成
- Webサーバー
- nginx
- WSGIサーバー(APサーバー)
- Gunicorn
- Webアプリケーションフレームワーク
- Django
- ここではWSGIを使用するので、WSGIに準拠していれば他のフレームワークでも良い
- この記事ではDjango固有の設定は発生しない
- WebサーバーとWSGIサーバーはDockerコンテナで稼働させる
- WebサーバーとWSGIサーバーの通信にはUNIXドメインソケットを使用する
用語の整理
WSGIサーバーとは
- WSGIとはWeb Server Gateway Interfaceのことで、WebサーバーとPythonのAPサーバー間通信のプロトコルのこと
- DjangoやFlask、Bottleなどのフレームワークもこのプロトコルに準拠している
- 上記のWSGIに則ったAPサーバーをWSGIサーバーと呼び、Gunicornはその一種
- gunicorn以外のWSGIサーバーにはuWSGIがある
UNIXドメインソケットとは
- ファイルシステムのパスを通して通信相手を探す通信方法
- そのパスにファイルが作成され、それぞれのプロセスがそのファイルにアクセスする
- 単にファイルを共有しているだけに思えるが、作成されるファイルはソケットファイルと呼ばれる特殊なファイルであり実態はない
- あくまで通信のインターフェース
構築
Gunicorn
- まずはWSGIサーバーを単体で稼働させてみる
プロジェクト作成
- Djangoをインストールする
$ pip install Django==3.0.2
- 作業環境でプロジェクトを作成する
$ django-admin.py startproject django_project .
- ここではdjango_projectという名前でプロジェクトを作成
- treeコマンドで確認すると以下のようになる
$ tree . ├── django_project │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.pyGunicornコンテナ起動
- Dockerfileを作成
FROM python:3.8.0-alpine WORKDIR /usr/src/app ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 RUN pip install --upgrade pip COPY ./requirements.txt /usr/src/app/requirements.txt RUN pip install -r requirements.txt
- requirements.txt は以下の通り
requirements.txtDjango==3.0.2 gunicorn==20.0.4
- ビルドする
$ docker build -t gunicorn:tmp .
- docker-compose.yamlの記載は以下の通り
- 後でnginxの情報も追記する
version: '3.7' services: gunicorn: image: gunicorn:tmp container_name: gunicorn command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/usr/src/app/ ports: - 8000:8000
python manage.py runserver 0.0.0.0:8000
コマンドでテスト用簡易サーバーが起動される- ここでは稼働確認のため8000番のポートをフォワーディングしている
$ docker-compose up -d
で起動してlocalhost:8000にアクセスしてDjangoの画面が表示されればOKNginxでUNIXドメインソケット使用する設定
- 公式のDockerイメージを使用するが、UNIXドメインソケットの設定を記載したconfファイルを作成し起動時にマウントさせる
- gunicorn.confという名前で以下の内容を記載
gunicorn.confupstream gunicorn-django { server unix:///var/run/gunicorn/gunicorn.sock; } server { listen 80; server_name localhost; location / { try_files $uri @gunicorn; } location @gunicorn { proxy_pass http://gunicorn-django; } }
upstream gunicorn-django{…}
の内容がUNIXドメインソケットの設定- 記載したパスのソケットファイルを介することでgunicornと通信を行う
- つまりgunicorn側からもこのソケットファイルを呼び出す設定が必要になる
- あとはlocationのproxy_passでupstreamで指定したgunicorn-djangoを指定すればよい
- Nginxのdocker-compose.yamlの記載は以下の通り
version: '3.7' services: nginx: image: nginx:1.17.7 container_name: nginx ports: - "80:80" volumes: - ./gunicorn.conf:/etc/nginx/conf.d/default.conf
- Nginx内に
/etc/nginx/conf.d/default.conf
という名前でマウントする- Nginxは/etc/nginx/nginx.confを起動時に読み取り、そのファイル内で
include /etc/nginx/conf.d/*.conf;
という記載がされているため、/etc/nginx/conf.d
配下に自分で作成したconfファイルをマウントしておけば起動時に一緒に読み込んでくれるGunicornでUNIXドメインソケット使用する設定
- 先ほどローカルで起動させた状態から多少変更を加える
コンテナの起動コマンド
WSGIの設定
- GunicornがNginxと通信を行えるよう、以下のようなgunicornコマンドを叩く必要がある
gunicorn django_project.wsgi
- これは今回django_projectというプロジェクトを作成したときに構築されるdjango_project配下にあるwsgi.pyを読み込む
- ローカルで起動させるときはmanage.pyを起動させたが、WSGIで通信させるときはこのコマンドが必要になる
UNIXドメインソケットの設定
- UNIXドメインソケットで通信させるため、
--bind
で起動時ソケットファイルのパスを指定するgunicorn django_project.wsgi --bind=unix:/var/run/gunicorn/gunicorn.sock
- これによりgunicornへのUNIXドメインソケット通信が可能になる
Doickerfile修正
- 上記の内容を基に、DockerfileのCMDを変更
DockerfileFROM python:3.8.0-alpine WORKDIR /usr/src/app ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 RUN pip install --upgrade pip COPY ./requirements.txt /usr/src/app/requirements.txt RUN pip install -r requirements.txt RUN mkdir -p /var/run/gunicorn CMD ["gunicorn", "django_project.wsgi", "--bind=unix:/var/run/gunicorn/gunicorn.sock"]
- 再度ビルドしておく
$ docker build -t gunicorn:latest .Djangoプロジェクトへアクセスできるホストを指定
- django_project配下に作成されるsetting.py内の
ALLOWED_HOSTS=[]
に指定する- 本来なら制限するべきだが、ここでは全てのホストからのアクセスを許可するため
ALLOWED_HOSTS=[*]
にしておく- このファイルはwsgi.pyから呼び出されている
UNIXドメインソケット通信でマウントするボリュームを作成
- Nginx、Gunicornでソケットファイルのパスを指定したので、ソケットファイルのボリュームを作成する必要がある
- 今回はDockerで起動させるので、DockerのVolumeを起動時に作成し、2つのコンテナからそのVolumeにマウントを行う
- 最終的なdocker-compose.yamlは以下の通り
docker-compose.yamlversion: '3.7' services: gunicorn: image: gunicorn:latest container_name: gunicorn volumes: - .:/usr/src/app/ - gunicorn:/var/run/gunicorn nginx: image: nginx:1.17.7 container_name: nginx depends_on: - gunicorn ports: - "80:80" volumes: - ./gunicorn.conf:/etc/nginx/conf.d/default.conf - gunicorn:/var/run/gunicorn volumes: gunicorn: driver: local
- gunicornというVolumeを作成し、それぞれのコンテナにマウントする(今回はどちらのコンテナでも
/var/run/gunicorn
を指定している)稼働
- 以下のコマンドで起動
$ docker-compose up -d Starting gunicorn ... done Starting nginx ... done
- 起動後に
localhost
にアクセスしてみる
- 画面が表示されればOK
- 最初にGunicornを単体で稼働させたときと表示されている画面は同じだが、今回はnginxを経由して表示されている
ソースコード
- 今回作成したファイル一式はこちら
参考
- 投稿日:2020-02-08T15:18:15+09:00
Rubyで学ぶ「ゼロから作るDeep Learning」Docker環境構築編
Dockerの環境構築
やること
- ローカルのワーキングディレクトリを作成
- DockerでRubyの環境を作成
- Dockerで作成したワーキングディレクトリをマウントして環境に入る
- Dockerに必要なパッケージ等をインストール
- gnuplot & numo-gnuplot
- プロット用
- numo-narray
- 行列計算 & 基礎的な数学の関数(sin cos exp等)
Docker環境を作って、ワーキングディレクトリをマウントする所まで
実行コマンド
# ローカルにワーキングディレクトリを作成 local$ mkdir working_dir # RubyのDockerイメージを取得 local$ docker pull ruby:latest # ワーキングディレクトリをマウントしてDocker環境に入る local$ docker run -v /(workingディレクトリをおいているパス)/working_dir/:/working_dir/ -it ruby /bin/bashなぜワーキングディレクトリをマウントしておくか
gnuplotで出力したファイルを、Dockerファイルシステムの外で簡単に確認できる。ローカル環境にコピーするコマンドを叩かず、手元の環境(macOS)のプレビューアプリ等で出力したpngイメージを確認できるので便利。他にも、特に設定せずに、自分のお気に入りのエディタを使えるのもよい。
Dockerに必要なパッケージ等をインストール
# gunuplotのインストール docker$ apt update -y && apt upgrade -y && apt install -y gnuplot # 各種gemのインストール docker$ gem install numo-narray numo-gnuplotとりあえず動かしてみる
ローカルのワーキングディレクトリに先人の記事のファイルをそのまま作成
Python vs Ruby 『ゼロから作るDeep Learning』 1章 sin関数とcos関数のグラフ
https://qiita.com/niwasawa/items/6d9aba43f3cdba5ca725# ワーキングディレクトリへ移動 docker$ cd working_dir # 作ったファイルがあるかの確認 docker:working_dir$ ls sin_cons.rb # ←ちゃんとローカルで作ったファイルがある # 実行 docker:working_dir$ ruby sin_cos.rb docker:working_dir$ ls ruby_graph.png sin_cons.rb # ← 出力されている結果
備考:なぜRuby?
鳥取県米子市出身で、松江にサテライトオフィスを持つ企業で働いている為。
松江といえばMatzさん、Rubyの聖地。仕事でもRubyをつかうしね。
- 投稿日:2020-02-08T15:18:15+09:00
敢えてRubyで学ぶ「ゼロから作るDeep Learning」Docker環境構築編
Dockerの環境構築
やること
- ローカルのワーキングディレクトリを作成
- DockerでRubyの環境を作成
- Dockerで作成したワーキングディレクトリをマウントして環境に入る
- Dockerに必要なパッケージ等をインストール
- gnuplot & numo-gnuplot
- プロット用
- numo-narray
- 行列計算 & 基礎的な数学の関数(sin cos exp等)
Docker環境を作って、ワーキングディレクトリをマウントする所まで
実行コマンド
# ローカルにワーキングディレクトリを作成 local$ mkdir working_dir # RubyのDockerイメージを取得 local$ docker pull ruby:latest # ワーキングディレクトリをマウントしてDocker環境に入る local$ docker run -v /(workingディレクトリをおいているパス)/working_dir/:/working_dir/ -it ruby /bin/bashなぜワーキングディレクトリをマウントしておくか
gnuplotで出力したファイルを、Dockerファイルシステムの外で簡単に確認できる。ローカル環境にコピーするコマンドを叩かず、手元の環境(macOS)のプレビューアプリ等で出力したpngイメージを確認できるので便利。他にも、特に設定せずに、自分のお気に入りのエディタを使えるのもよい。
Dockerに必要なパッケージ等をインストール
# gunuplotのインストール docker$ apt update -y && apt upgrade -y && apt install -y gnuplot # 各種gemのインストール docker$ gem install numo-narray numo-gnuplotとりあえず動かしてみる
ローカルのワーキングディレクトリに先人の記事のファイルをそのまま作成
Python vs Ruby 『ゼロから作るDeep Learning』 1章 sin関数とcos関数のグラフ
https://qiita.com/niwasawa/items/6d9aba43f3cdba5ca725# ワーキングディレクトリへ移動 docker$ cd working_dir # 作ったファイルがあるかの確認 docker:working_dir$ ls sin_cons.rb # ←ちゃんとローカルで作ったファイルがある # 実行 docker:working_dir$ ruby sin_cos.rb docker:working_dir$ ls ruby_graph.png sin_cons.rb # ← 出力されている結果
備考:なぜRuby?
鳥取県米子市出身で、松江にサテライトオフィスを持つ企業で働いている為。
松江といえばMatzさん、Rubyの聖地。仕事でもRubyをつかうしね。
- 投稿日:2020-02-08T14:07:24+09:00
RSpecにおいてActionController:RoutingError No route matches [GET] "/assets/〜"
前提
Dockerで開発
rails 5.2.1エラー内容
ActionController:RoutingError No route matches [GET] "/assets/〜"エラーが起こった状況
実装したcontrollerおよびテンプレートに対するテストを追加しようとした。
requests specについては、上記エラーは出なかった。
system specを作成しbundle exec rspecを実行すると、上記エラーが出てしまう。解決方法
config/enviroments/test.rbに以下を追加した。test.rbconfig.assets.paths << Rails.root.join('app', 'assets', 'images', 'plugins', 'rs-plugin', 'assets')エラーで出ていたassetsファイルがassets/images/plugins/rs-plugin/assetsにあるため上記コードを追加。
- 投稿日:2020-02-08T14:05:36+09:00
Docker
前回につづき、またもメモ気味な内容
前回は時間もなかったのでさくさくと書いてみた。
Dockerを始めてみよう今回はもう少しそこから進んでみる。
DockerHub
Dockerを使って環境を作成するというなら切っても切れない。
Docker Hub
指示に従い、普通に登録。Dockerイメージ
Dockerコンテナのベースになるもの。
DockerHubのExploreみるといろいろある。(ubuntu,Centos,nginx…などなど)
このDockerイメージを実行してコンテナが作成されるっぽい。
docker run <イメージ名>
※ちなみにこの「run」は
docker create <イメージ名>
と
docker start <イメージ名>
の合わせ技みたいね。Dockerコンテナ
Dockerといえばこのコンテナ
イメージから実行された仮想環境。
起動されたコンテナは任意で停止させないと起動しっぱなしなので、用が済んだら
docker stop <イメージ名>
とdocker rm <イメージ名>
を入力しておくか、最初からstopかけたら削除のコマンドを入れておくなりしておこう。Dockerファイル
Dockerイメージを作成するファイル
かるく作成してみたが、なかなか慣れが必要そう。
でも、これを使えるようになるとDockerイメージを自由に構成できるし、開発環境も統一出来そうっすね。いいね。
でも難しそう…おい、楽しいぞDocker
触ってみると難しいことは今のところはまだなさそう。
コンテナとかイメージをちゃんと説明できそうもないが実際にアプリ作れるようになるともう少し理解が進むかも。
- 投稿日:2020-02-08T14:05:36+09:00
Dockerを始めてみよう その2
前回につづき、またもメモ気味な内容
前回は時間もなかったのでさくさくと書いてみた。
Dockerを始めてみよう今回はもう少しそこから進んでみる。
DockerHub
Dockerを使って環境を作成するというなら切っても切れない。
Docker Hub
指示に従い、普通に登録。Dockerイメージ
Dockerコンテナのベースになるもの。
DockerHubのExploreみるといろいろある。(ubuntu,Centos,nginx…などなど)
このDockerイメージを実行してコンテナが作成されるっぽい。
docker run <イメージ名>
※ちなみにこの「run」は
docker create <イメージ名>
と
docker start <イメージ名>
の合わせ技みたいね。Dockerコンテナ
Dockerといえばこのコンテナ
イメージから実行された仮想環境。
起動されたコンテナは任意で停止させないと起動しっぱなしなので、用が済んだら
docker stop <イメージ名>
とdocker rm <イメージ名>
を入力しておくか、最初からstopかけたら削除のコマンドを入れておくなりしておこう。Dockerファイル
Dockerイメージを作成するファイル
かるく作成してみたが、なかなか慣れが必要そう。
でも、これを使えるようになるとDockerイメージを自由に構成できるし、開発環境も統一出来そうっすね。いいね。
でも難しそう…おい、楽しいぞDocker
触ってみると難しいことは今のところはまだなさそう。
コンテナとかイメージをちゃんと説明できそうもないが実際にアプリ作れるようになるともう少し理解が進むかも。
- 投稿日:2020-02-08T13:25:32+09:00
Dockerを使ったLaravelの環境構築
はじめに
最近は現場でも、Docker環境下でLaravleを触ることが増えて少しは知見も溜まってきたかと思いますので、忘れないように忘備録として残しておきます
ここでは、
docker
やdocker-compose
のインストールに関しては触れませんので、まだの方はこちらの記事がわかりやすかったので参考にしてみてください記事内の不備や、もっとこうした方がいいいよというアドバイスがございましたらコメントお願いします
構成
任意のディレクトリに
SampleProject
を作成して下記のディテクトり構成で環境を構築しますSampleProject ├── docker-compose.yml ├── docker │ ├── php │ │ ├── Dockfile │ │ └── php.ini │ └── nginx │ └── default.conf └── src └── Laravelのプロジェクトファイルdocker-compose.ymlの中身
docker-compose.yml
は複数のコンテナを同時に動かすためのツールである、Docker Compose
を利用するために使用するYAMLファイルですdocker-compose.ymlversion: '3' services: php: container_name: php-1 build: ./docker/php volumes: - ./src:/var/www nginx: image: nginx container_name: nginx-1 ports: - 80:80 volumes: - ./src:/var/www - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php db: image: mysql:5.7 container_name: db-host-1 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: sample_project MYSQL_USER: docker MYSQL_PASSWORD: docker TZ: 'Asia/Tokyo' command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: - ./docker/db/data:/var/lib/mysql - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf - ./docker/db/sql:/docker-entrypoint-initdb.d ports: - 3306:3306 node: image: node:12.13-alpine tty: true volumes: - ./src:/var/www working_dir: /var/wwwDockerfileの中身
Dockerfile
とはDocker上で動作させるコンテナの構成情報を記述するためのファイルですFROM php:7.2-fpm COPY php.ini /usr/local/etc/php/ RUN apt-get update \ && apt-get install -y zlib1g-dev mariadb-client \ && docker-php-ext-install zip pdo_mysql #Composer install RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" RUN php composer-setup.php RUN php -r "unlink('composer-setup.php');" RUN mv composer.phar /usr/local/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer ENV PATH $PATH:/composer/vendor/bin WORKDIR /var/www RUN composer global require "laravel/installer"php.iniの中身
php.ini[Date] date.timezone = "Asia/Tokyo" [mbstring] mbstring.internal_encoding = "UTF-8" mbstring.language = "Japanese"default.confの中身
default.conf
はngninxの設定情報を記述するためのファイルですdefault.confserver { listen 80; index index.php index.html; root /var/www/public; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }環境構築の手順
はじめに任意の場所に
SampleProject
を作成する~/ $ mkdir SampleProject
docker-compose.yml
ファイルを作成して、中身は冒頭で紹介したdocker-compose.yml
の内容をコピペする~/SampleProject $ touch docker-compose.yml
Dockerfile
とphp.ini
を作成して、中身は冒頭で紹介したそれぞれのファイルの内容をコピペする~/SampleProject/docker/php $ touch Dockerfile ~/SampleProject/docker/php $ touch php.ini
defalt.conf
ファイルを作成して、中身は冒頭で紹介したdefault.conf
の内容をコピペする~/SampleProject/nginx $ touch default.conf
docker-compose.yml
ファイルがあるディレクトリ内で下記コマンドを実行してdocker
を起動させる~/SampleProject $ docker-compose up -d Creating php ... done Creating db-host ... done Creating sampleproject_node ... done Creating nginx ... donephpのコンテナ内に入る
~/SampleProject $ docker-compose exec php bashphpコンテナ内でLaravelプロジェクトを作成する
root@7eb4359bf51c:/var/www# laravel newphpコンテナを抜ける
root@7eb4359bf51c:/var/www# exitこれで
SampleProject/src
内にLaravelのプロジェクトファイルが作成され、
http://localhost/ にアクセスするとおなじみのWelcomeページが表示されますMySQLコンテナに入る
~/SampleProject $ docker-compose exec db bashMySQLコンテナ内でMySQLにログイン
root@630fbaf32806:/# mysql -u root -proot今回のプロジェクトで使用するデータベースを作成する
データベース名はdocker-compose.ymlで指定した、MYSQL_DATABASE
と合わせる必要がありますmysql> mysql> CREATE DATABASE sample_project; Query OK, 1 row affected (0.01 sec)Laravelのプロジェクトファイル内の
.env
ファイルを下記に修正する.envDB_CONNECTION=mysql DB_HOST=db # docker-compose.ymlに記載したDBのサービス名 DB_PORT=3306 DB_DATABASE=sample_project # 使用するDB名 DB_USERNAME=root DB_PASSWORD=rootphpコンテナに入る
~/SampleProject $ docker-compose exec php bashphpコンテナ内でマイグレーションを実行する
root@7eb4359bf51c:/var/www# php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.06 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.04 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.02 seconds)マイグレーションが無事に実行されれば成功です!!
- 投稿日:2020-02-08T12:26:46+09:00
#Docker hub から pull するときのメジャー・マイナー・パッチバージョン指定
https://hub.docker.com/_/alpine
ゆるい指定をしたときは、最新版を pull するというような運用をしているイメージが多いだろう。
同じイメージなのかどうかを確認するには pull したときの Digest が同じかどうかを見ることで確認できそうだ。
$ docker pull alpine:latest Digest: sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d $ docker pull alpine:3 Digest: sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d $ docker pull alpine:3.11 Digest: sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d$ docker pull alpine:3.10 Digest: sha256:7c3773f7bcc969f03f8f653910001d99a9d324b4b9caa008846ad2c3089f5a5f $ docker pull alpine:3.10.4 Digest: sha256:7c3773f7bcc969f03f8f653910001d99a9d324b4b9caa008846ad2c3089f5a5fゆるい指定の場合は、pullする時期によって、別のものが取れてしまう
Dockerfileなどに書くときは、なるべくマイナーバージョン、パッチバージョンまで指定しておきたい
Original by Github issue
- 投稿日:2020-02-08T11:20:29+09:00
docker-compose buildでNOTICE: chromedriver-helper is deprecated after 2019-03-31.と出た時の対処法
docker-compose buildとgemfileをアップデートをしたときに、エラーにはならなかったが
NOTICE: chromedriver-helper is deprecated after 2019-03-31. Please update to use the 'webdrivers' gem instead. See https://github.com/flavorjones/chromedriver-helper/issues/83という注意喚起のメッセージが出た時の対処法について、僕が解決した方法を書いていこうと思います。
メッセージの意味
NOTICE: chromedriver-helper is deprecated after 2019-03-31. Please update to use the 'webdrivers' gem instead. See https://github.com/flavorjones/chromedriver-helper/issues/83まずこの注意喚起の文章の意味を知らないことには話が進まないので、これを日本語訳していこうと思います。
結論、この文章は
chromedriver-helperはサービス終了したのでwebdrivers gemに変更してください。
という意味の文になります。
対処法
意味が分かれば対処は簡単です。まずはgemfileを開いてください。
gemfileの
group :test doの中のchromedriver-helperを消してwebdriversに書き直します。
そして再び
docker-compose buildを実行するとこの注意喚起の文は表示されなくなっていると思います。参考になれば幸いです。
- 投稿日:2020-02-08T10:31:40+09:00
Dockerで脆弱性WebアプリケーションDVWA構築
DockerでDVWA構築
今回は、Dockerで脆弱性WebアプリケーションであるDVWAの構築手順をまとめていきたいと思います。
DVWAを構築する目的は、攻撃手法を学び、より安全なWebアプリケーションを作成するためです。
そのため次回以降の記事では、SQLインジェクション、CSRF、XSSといったことにも触れていきたいと思います。
DVWAはPHP/MySQL製の脆弱Webアプリケーション
DVWA(Damn Vulnerable Web Application)は、PHP/MySQL製のセキュリティ脆弱性のあるWebアプリケーションです。
このDVWAに様々な攻撃を仕掛けることによってユーザーの情報を取得できるので、脆弱性を産む可能性のあるコードについて学ぶことができます。
またセキュリティレベルをLow、Medium、Highに設定できるので、基礎的な攻撃手法から応用的なものまで学ぶことができます
Dockerで簡潔にDVWA構築
今回はより短時間で容量をくわず構築するため、DockerでDVWAのイメージをプルし構築しました
前提条件
- yum updateしたCentOS7サーバー(グローバル接続済み)
DVWAのイメージをプルして起動
まず、初期状態なので、dockerをインストール。
# yum install docker続いてdockerコマンドで、DVWAのイメージをプル(インストール)します。
# docker pull infoslack/dvwa続いて、HTTPの外部からアクセスされるポート番号を80、コンテナ側のポート番号を80、MySQL側も外部からアクセスされるポート番号を3306、コンテナ側のポート番号を3306に指定し、バックグラウンドでdockerを起動します。
# docker run -d -p 80:80 -p 3306:3306 -e MYSQL_PASS="mypass" infoslack/dvwaここまでできたら、グローバルIPアドレス/setup.php(グローバルに繋がっているサーバーの場合)にアクセスすると、DVWAのセットアップ画面がでます。
create/Reset Databaseを選択し、パスワード入力画面でUsernameをadmin、Passwordをpasswordと入力。
無事ログインできたら、DVWAの構築は完了です。
参考URL
https://www.pupha.net/archives/1297/
https://securitybytes.io/docking-dvwa-be9abf862210
- 投稿日:2020-02-08T09:43:18+09:00
仕事中にこっそりヒーリングっどする
できること
cureutils で無限の癒やしを得る。
※注意点
- プリキュア初心者(ヒーリングっどプリキュアが初プリキュア)です。
- ヒーリングっどプリキュアのヒロインたちは実装されていません(タイトル詐欺)。
- この記事は湧いた頭を冷ますために書いたものです。過度な期待はしないでください。
- 技術的なものは何も得られません。
何があったのか
顧客をコントロールできないPM、納期直前まで続く仕様変更、メンバーはわがままばっかり言う、連日の午前様。
もぅマヂ無理。
癒やし、癒やしが欲しい……。合間合間の気分転換。
Tera Term の小さな画面、fortune が吐き出した言葉たちを眺める。こんな感じ。
$ while :; do fortune; sleep 300; echo -e "\n"; done Electrocution, n.: Burning at the stake with all the modern improvements. Last week a cop stopped me in my car. He asked me if I had a police record. I said, no, but I have the new DEVO album. Cops have no sense of humor. We are all agreed that your theory is crazy. The question which divides us is whether it is crazy enough to have a chance of being correct. My own feeling is that it is not crazy enough. -- Niels Bohrでも、アメリカンなジョークはよくわからない……。
もっと癒やされたい……。
なにかないか……。あった……!
ありがとうございます、ありがとうございます。
面白そうなものを見つけてしまったからには、使ってみなくてはならない。
コンテナ化
開発環境を汚したくなかったので、Docker で実行環境を用意した。
ついでにコマンド一発でプリティでキュアキュアな口上を述べて頂けるようにした。使い方
docker-compose.yml
はこう。version: '3' services: app: image: ancolin/cureutils:latest environment: - USE_IN_BATTLE=TRUE # TRUE: 戦闘中のセリフを使う - ONLY_USE_IN_BATTLE=FALSE # TRUE: 戦闘中のセリフだけ使う - PRINT_QUICK=FALSE # TRUE: セリフをまとめて表示する - HUMAN_NAME= # 名前: 特定のヒロインのセリフだけ使うこんな shell スクリプトを書くと実行が楽ちんで良い。
$ cat cure.sh #!/bin/sh set -eu cd /home/ancolin/docker/docker-cureutils while :; do docker-compose run --rm app sleep 60 echo -e "\n" done $ ./cure.sh スカイローズ・トランスレイト! 青いバラは秘密のしるし! ミルキィローズ! by 美々野くるみ / ミルキィローズ (milky_rose) チェインジ!プリキュア・ビートアップ! ブルーのハートは希望のしるし! つみたてフレッシュ、キュアベリー! レッツプリキュア! by 蒼乃美希 / キュアベリー (cure_berry)もともとの cureutils の機能も使える。
$ docker-compose run --rm app cure version Cureutils 1.2.0 $改善効果
世の中の仕組みを理解できた。
- PMは顧客をコントロールできない。
- 仕様変更は納品したあとも続く。
- メンバーは簡単に辞める(病める)。
- マイカーorタクシーなら24/7通勤可能。
それでもくじけないポジティブな心を得ることができる(できたとは言ってない)。
宣伝
プリキュアって戦士だったんだね、魔法少女じゃないんだね、知らなかったよ。
みんなもプリキュアみよね。
プリキュア
- 投稿日:2020-02-08T09:31:53+09:00
MacでDocker+Rails+MySQL環境構築手順メモ
勉強するときに環境構築にかなりつまづいたので、その手順をメモしときたいと思います。
環境構築手順
前提として、rails開発用のディレクトリが用意されているものとします。
以下の手順に従ってファイル作成やコマンドを実行していけば問題なく手順は整うと思います。
Dockerfileの作成(以下をコピペ)
# rubyはお好みのバージョンで(ローカルのバージョンがいいと思います) FROM ruby:2.6.3 # 必要なパッケージのインストール(基本的に必要になってくるものだと思うので削らないこと) RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ nodejs # 作業ディレクトリの作成、設定 RUN mkdir /app_name ##作業ディレクトリ名をAPP_ROOTに割り当てて、以下$APP_ROOTで参照 ENV APP_ROOT /app_name WORKDIR $APP_ROOT # ホスト側(ローカル)のGemfileを追加する ADD ./Gemfile $APP_ROOT/Gemfile ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock # Gemfileのbundle install RUN bundle install ADD . $APP_ROOTGemfileの作成(以下をコピペ)
source 'https://rubygems.org' #好きなバージョンを指定 gem 'rails', '5.2.2'空のGemfile.lockの作成
何も書かなくていいです。
docker-compose.ymlを作成(以下をコピペ)
docker-compose.ymlversion: '3' services: db: image: mysql:8.0.17 command: mysqld --default-authentication-plugin=mysql_native_password volumes: - ./db/mysql_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: root ports: - "4306:3306" web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0' volumes: - .:/app_name ports: - "3000:3000" links: - dbターミナルでrails newを実行
$ docker-compose run web rails new . --force --database=mysql --skip-bundle上のコマンドを打ってしばらく待つ
database.ymlを修正(一度全て消してから以下をコピペ)
database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= ENV.fetch("MYSQL_USERNAME", "root") %> password: <%= ENV.fetch("MYSQL_PASSWORD", "root") %> host: <%= ENV.fetch("MYSQL_HOST", "db") %> development: <<: *default database: app_name_development test: <<: *default database: app_name_test production: <<: *default database: app_name_production username: app_name password: <%= ENV['APP_NAME_DATABASE_PASSWORD'] %>ターミナルでDockerを起動
docker-compose buildしばらく待つ。できたら以下を実行。
docker-compose upDB作成
別のターミナルを開いて以下を実行
docker-compose run web rails db:createブラウザでlocalhost:3000にアクセス
サーバーが起動してたらおk。
サーバーを止める
docker-compose downサーバーを再起動
docker-compose upまとめ
これでrailsアプリ作成の準備が整うはずです。
環境構築は完全に初見ごろしだと思うので誰かの助けに慣れたら嬉しいです。
また、何かおかしい点とかあれば言って頂けるとありがたいです。お付き合い頂きありがとうございました。
参考サイト
- 投稿日:2020-02-08T00:28:45+09:00
Dockerを使用したRails環境の構築について
はじめに
Railsのチュートリアルを始める際に、DokerによるRails環境構築方法を備忘録的にまとめました。
間違い等ございましたら、ご指摘いただけると嬉しいです。
(ちょっと…自分が書いたのを見返してみたら、自分用とはいえ文章のクオリティがすこぶる悪い気がするので、いずれ修正します…。)環境と自己紹介
- PCはWindows
- Docker for Windows
- Ruby 2.5.3
- Mysql 5.7
- Rails 5.1.6(最終的に5.1.7がインストールされていました。。)
- Heroku
(上記はいずれも、現時点でのRailsチュートリアルに沿ったツール、バージョンにしたつもりです。)
GitHub
(チュートリアルではprivateにするため、Bitbucketを使用していますが、GitHubでもprivateにできそうなのでGitHubにしてみました。)プログラマでも何でもありません。IT系の企業でもない会社でIT担当してます。
普段はコードは書きません。年齢もそこそこなので、半分趣味の世界ですが、何か自分や会社の役に立てたいと思います。
プログラムにはPython(Django)から入り、チュートリアルをポチポチ進めました。
いずれ、頑張ってCircleCIやAWSの環境を組み込んでいければいいなと思います。
■ チュートリアル前の準備
コードを書き始める前に、必要な各種ファイルの準備を進めていきます。
自分の中で、どこの記述がどこに関連しているのかがわかりにくかったので、コメント多くして整理してみました。1. Gemfile、Gemfile.lockを準備
まずは、GemfileとGemfile.lockを作成しました。
Gemfile.# 最初はこの2行だけ。 # gemのダウンロード元のURL source 'https://rubygems.org' # gemとバージョンを指定 gem 'rails', '5.1.6'Gemfile.lock# 空の状態で作成しました。
2. Docker関係の準備
続いて、Dockerfileとdocker-compose.ymlを準備しました。
Dockerfile.# このイメージをもとにして、以降、Railsに必要なパッケージなどを追加していく。 FROM ruby:2.5.3 # コンテナ内で実行するコマンドを定義 # Railsに必要なパッケージのインストール(build-essentialとnodejs) RUN apt-get update -qq && apt-get install -y build-essential nodejs # rootディレクトリにappディレクトリを作成し、appへ移動 # 今後Railsのプロジェクトファイルはappディレクトリ内に作成される。 RUN mkdir /app WORKDIR /app # GemfileとGemfile.lockをPC上からコピー COPY Gemfile /app/Gemfile COPY Gemfile.lock /app/Gemfile.lock # Gemfileに記述されたgemをインストールする # Railsもgemで公開されているため、GemfileにRailsとそのバージョンを書いておく # これにより、Rubyのコンテナ内に、GemfileをもとにRailsがインストールされる。 RUN bundle install # Dockerfileが置いてあるフォルダの内容をコピーする # Railsのアプリケーション実行に必要なファイルをすべてコンテナの中に含める COPY . /appdocker-compose.yml# docker-compose.ymlのバージョン version: '3' # サービスを定義する。ここでは、webとdbの2つ services: # web定義ここから web: build: . # docker-compose.ymlと同じフォルダにあるDockerfileからイメージをビルドする。 command: bundle exec rails s -p 3000 -b '0.0.0.0' # デフォルトで実行するコマンドを記載。ここではrailsのサーバー起動。 volumes: # PC上のディレクトリをコンテナ上のappディレクトリにマウント。PC上の修正がコンテナにも反映される。 - .:/app ports: # コンテナ外部に3000ポートを開放。<コンテナ外に公開するポート>:<コンテナ内で転送されるポート> - "3000:3000" depends_on: # webコンテナが起動する前にdbが起動するようにする。 - db tty: true # コマンドラインでの操作やコマンドの出力結果を対話的にうための疑似ttyを割り当てる。pryを使用するために必要。 stdin_open: true # 標準入力を開き続ける。これがないと、docker exec -itでコンテナを操作できないんだと思う。 # web定義ここまで # db定義ここから db: image: mysql:5.7 # mysql5.7のイメージからビルドする。 environment: # コンテナ内の環境変数に設定する。 MYSQL_ROOT_PASSWORD: password # mysqlのrootパスワード ports: - '3306:3306' # コンテナ外部に3306ポートを開放し、コンテナ内の3306に転送する。 volumes: # これがないと、データはコンテナ内に直に保存されるが、コンテナ削除時にデータも消えてしまう。 - mysql_data:/var/lib/mysql # db定義ここまで # volume定義ここから volumes: # PC上にデータを保持するための領域を作成する。 mysql_data: # volume定義ここまで3.環境構築
実際に、コマンドを打って環境を構築してみました。手順はこんな感じで行いました。
(解釈に間違いありましたらご教示ください。。)1.
$ docker-compose run web rails new . --force --database=mysql
→これにより、新しいRailsのプロジェクトが作成される。
この時は、Gemfileにはrailsのみが記載されているので、
rubyのイメージをベースとして、railsがインストールされたイメージがビルドされる。
2.--force
オプションをつけているので、Gemfile、Gemfile.lockにgemのインストールが追記(上書き)される。
→この時点では、追記されたgemはまだイメージにインストールされていない。
「new .」の「.」はPC上のカレントディレクトリを意味している。
新しいRailsプロジェクトの各ファイルはカレントディレクトリ上に作成される。
3.--database=mysql
を指定しているので、config/database.ymlの設定がMySQLになる。
(標準はSQLite3)
3.$ docker-compose build
→このコマンドにより、Gemfileに追加されたgemがインストールされたイメージがビルドされる。
Dockerfileの最後の行にある COPYにより、作成された各ファイルが、
カレントディレクトリから、イメージ上のappディレクトリにコピーされる。4.データベースの接続設定
/config/database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password # docker-composer.ymlに設定したパスワード host: db # docker-compose.ymlに作成したdbのサービス名5.サーバーの起動
サーバーを起動します。
$ docker-compose up -d
と入力してサーバーを起動します。test_db_1 is up-to-date Creating test_web_1 ... doneとなりました。
$ docker-compose ps
でコンテナが起動しているか確認します。Name Command State Ports --------------------------------------------------------------------------------------- test_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp test_web_1 bundle exec rails s -p 300 ... Up 0.0.0.0:3000->3000/tcpただ、今の状態では、webとdbのコンテナが立ち上がったのみで、
dbのコンテナにはデータベースが作成されていない状態なので、
次のステップでdbコンテナのmysqlにデータベースを作成する。6.開発環境用のデータベースを作成する
$ docker-compose run web bundle exec rake db:create
Starting test_db_1 ... done Created database 'app_development' Created database 'app_test'7.Webページにアクセスして確認
localhost:3000
にアクセスしてみました。。。railsのバージョンを5.1.6と指定したつもりが、5.1.7になっているのは…如何に。
- 投稿日:2020-02-08T00:24:59+09:00
[Docker]クソ重いHello, World!イメージを劇的に軽くする
Docker v17くらいからMultiStageBuildという機能が実装されています。
今まで、「Hello,Worldを出力するだけのImageなのに、ベースImageサイズが大きくて、結局出来上がるImageも数百MBになるんだけど、、、」と、なっていたものが、BuildはGoのImage,実行はalpineのImageとできるようになりました。(v17以前でもできなくはなかったけど、めんどくさかった)
これが一体どういうことなのかをみていきたいと思います。今回は、
Hello, World!
を出力するコンテナを作成していきます。main.gopackage main import "fmt" func main() { fmt.Println("Hello, World!") }MultiStageBuildを使わない場合
Dockerfileは以下のようになります。
FROM golang:1.13.7-alpine3.11 COPY ./main.go ./ RUN go build -o ./hello ./main.go ENTRYPOINT ["./hello"]それぞれ同じディレクトリに存在する状態で、以下のコマンドを打ってみましょう。
$ docker build -t hello:0.1 .ビルド出来たらRunしてみます。
$ docker run hello:0.1 Hello World!ちゃんとmain.goがbuildされて、実行されました。では、この時のImageサイズをみてみます。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello 0.1 ea6e8238c063 49 seconds ago 361MB golang 1.13.7-alpine3.11 87eefb76f0a8 9 days ago 359MBこのように、golangのcontainer Imageがベースになっているため、サイズが大きくなっています。
Hello, World!
を出力するだけのコンテナなのに、これじゃあ重すぎですね。。。MultiStageBuildを使う場合
Dockerfileは以下のようになります。
#Stage 1 FROM golang:1.13.7-alpine3.11 as builder COPY ./main.go ./ RUN go build -o /hello ./main.go #Stage 2 FROM alpine:3.11 COPY --from=builder /hello . ENTRYPOINT ["./hello"]Stage1はgolangのImageを使っていて、ここでmain.goをbuildしています。そしてその実行ファイルをStage2に持ってきて、こっちで実行すると言う形です。
$ docker run hello:0.1 Hello World!こちらもちゃんと実行されました。同様に、Imageのサイズをみてみます。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello 0.1 15f814bf3a87 12 seconds ago 7.6MB <none> <none> 6f908ead16f8 13 seconds ago 361MB golang 1.13.7-alpine3.11 87eefb76f0a8 9 days ago 359MB alpine 3.11 e7d92cdc71fe 2 weeks ago 5.59MBここで
<none>
はStage1のImageで、<hello>
がStage2のImageになっています。Hello, Worldを出力するImageは<hello>
なので、そのサイズなんと7.6MBです!MultiStageBuildを使わない場合と比べて約350MBもImageサイズを削減することを実現できました!!まとめ
ということで、今回はDockerのMultiStageBuildの機能について、触れてみました。サイズの重たいBuild環境を分離することで、Imageサイズの削減を可能にすることを挙げましたが、他にもStageで分けることで、Dockerfileの保守のしやすさが上がる、セキュリティに強くなるなど、良い事が沢山あります!みなさまも使った事がない方は一度チャレンジしてみてください!
- 投稿日:2020-02-08T00:15:14+09:00
ボリューム(volumes)で何ができるか気づけたから解説!(docker-compose)
はじめに
Dockerって機能多すぎて、とりあえず実装して何も理解してないケースありませんか?
僕はボリュームがそのうちの1つでした...。『これから
Docker
やdocker-compose
を使い始める!』『volumes
が何をしているのか分からない...』という方には是非見て頂きたい記事となっております!これを読むことで何が分かるのか
- Dockerのボリュームとは何か分かる
- docker-composeのvolumesに何を設定するべきか分かる
docker volume ls
をした時に何故か増えてるボリューム達が何なのか分かる- DockerにてNginxを使いたい時に、コンテナ間のリソース共有実装の足がかりになる
データを永続化するとは
突然ですが、貴重なデータが含まれているデータってシンプルに消えてほしくないですよね(。・_・。)
そんな貴重なデータをDockerにてDB(データベース)コンテナとして起動させていると、docker ps
コマンドにて以下の画像のようにDBコンテナ(postgreSQL)が立ち上がっていることが確認できますよね。
ここでもし誤ってDBコンテナを消してしまう事があったら、どうなってしまうでしょうか...
DBに蓄積してきたデータが全て消えます。
ですがコンテナ管理において、デファクトスタンダードとされているDocker様がそんな状況を放置するでしょうか?いや否です。
コンテナのデータを別の場所で保管できるボリューム機能があります!
ボリュームを使えば、例えDBのコンテナを消してしまっても、データを別場所にて保管しているので、復元できるという仕組みですね(/・ω・)/
ボリュームとは
こちらは僕が説明するよりコチラの記事(Docker、ボリューム(Volume)について真面目に調べた - Qiita *1)の説明が優れていると思ったので、引用させていただきます。
- ボリュームとは、データを永続化できる場所のことである。
- 外部HDDのようなイメージ。コンテナ本体にマウントして使う。
コンテナ
とボリューム
の違いについて
- コンテナ内部にデータ(ファイル)を保存しても、コンテナ破棄すると消えてしまう。
- なので、データを永続化したいときは、コンテナの外にデータを置く必要がある。
- その場所のことを、ボリュームと呼ぶ。
ボリューム
(=データを永続化できる場所) は2種類ある。
- ホストのディレクトリ(ファイル)
- ホストで ls で見えるモノ。
- Docker の リソースとしての Volume
- docker volume ls で見えるモノ。
- (本当は、これ以外にもNFSなども指定できるようだ)
- ボリュームをコンテナにマウントすることで、コンテナからアクセスできるようになる。
- あるいは
--volumes-from <コンテナ名>
とすると、指定したコンテナのマウントと同じようにマウントできる。今までの僕のdocker-composeは...?
まずは『こんな記事にわざわざ見に来ていただいて感謝』ということで、恥ずかしながらも前まで設定していた駆け出し
docker-compose
を公開します。笑docker-compose.ymlversion: "3" services: db: # データベース(つまり消えて欲しくない貴重なデータ群)が含まれているプログラム達 image: postgres environment: - POSTGRES_USER - POSTGRES_PASSWORD ports: - "5432:5432" back: # バックエンド(静的ファイル配信やmodelの定義、routing設定など)のプログラム達 build: . volumes: # 注目 - .:/code # 注目 ports: - "8000:8000" command: gunicorn config.wsgi -b 0.0.0.0:8000 # サーバー起動 depends_on: - db上記の『ボリュームとは』から言うと、
volumes: - .:/codeという記述は、
ホスト側のディレクトリ(カレントディレクトリ化)
がコンテナ内(code下)
をマウントして、バックエンドのプログラムを永続化しているということになります(/・ω・)/dbにはvolumesを記述していないので、もちろん消えて欲しくない貴重なデータが含まれたデータベースは永続化していません!?!?
もう序盤で既にオチを悟った方もいるかもしれませんが(笑)、詳しくおかしな点について解説していきますね!
余談(ここはスルーしてOKです)
恐らくこれを見た経験者は『いやそこボリュームとしてデータ永続化してどないすんねん!』と言うでしょう。笑
しかも事前にvolumeの名前も定義もしていないので、docker volume ls
でボリューム一覧を出力した時にも、どれがどのボリュームなのかわからない。
やはり独学で実装していると、docker volume ls
した時に知らないボリュームが増えていくことに『違和感』を覚えることはありましたが、『おかしい』ことを確信せずに実装していたのです。なぜ勉強することになったか?
現在(2020/2/7)開発中である投票サービス《Shappar》で静的ファイルをDocker×Nginxで配信しようと思ったところ、以下の記事を見つけました。
DjangoをDocker Composeでupしよう! *2
↑上記事は要約すると『DjangoをGunicorn×Nginx×docker-composeを使ってサーバーを立ち上げよう!』というものです。そこで
docker-compose
の使用例として以下のような記述を見つけました。docker-compose.ymlversion: '3.7' services: django: restart: always build: ./django expose: - "3031" depends_on: - postgres command: bash -c "python manage.py migrate && gunicorn my_docker_project.wsgi -b 0.0.0.0:3031" volumes: - "staticdata:/opt/static/" # 3. ナンダコレ nginx: restart: always image: nginx depends_on: - django ports: - "80:80" volumes: - "./nginx/:/etc/nginx/" # 1. ナンダコレ - "staticdata:/opt/apps/static/" # 1. ナンダコレ 3. ナンダコレ postgres: image: postgres ports: - "5432:5432" volumes: - "dbdata:/var/lib/postgresql/data" environment: POSTGRES_PASSWORD: hogemojahogemoja volumes: # 2.ナンダコレ dbdata: staticdata:この記述を見て思った異変(自分の無知)の数々
./nginx/:
って...下のdbdata:
みたいにカンマスラッシュ
付けずにnginx:
←こうやって書き方統一しろよな!(※ヤバい間違いをしています。)- なんか一番下に
volumes
おる...- なぜ2回も
staticdata
を指定しているのだ...先ほどの疑問点について勉強を開始
1. ディレクトリの記述方法について
とりまdockerの公式docs *3に飛びます。すると以下の記述がありました。
docker-compose.ymlvolumes: # 1.パスを指定したら、Engine はボリュームを作成 - /var/lib/mysql # 2.絶対パスを指定しての割り当て - /opt/data:/var/lib/mysql # 3.ホスト上のパスを指定する時、Compose ファイルからのパスを指定 - ./cache:/tmp/cache # 4.ユーザの相対パスを使用 - ~/configs:/etc/configs/:ro # 5.名前付きボリューム(Named volume) - datavolume:/var/lib/mysq記述によって動作が全く違う件
引用してきた上記の
docker-compose
から、僕が疑問に思った記述方法は③と⑤に当てはまります。結論から言うと、
./nginx/:/etc/nginx/
とnginx:/etc/nginx/
とでは、プログラムの実行内容が全然違います。
./nginx/:
docker-compose.yml
が存在しているディレクトリから、相対パスによってマウントする側の指定先としてホスト側のディレクトリ
の指定を行います。nginx:
この書き方をすると、マウントする側の指定先として nginx
という名前付きボリューム
を探します。マウントする側の指定方法として、
./nginx/:
はカレントディレクトリから〜、対してnginx:
は名前付きボリューム
ありきで〜、というように方法が全く異なっていますね。はて?名前付きボリュームですか。
2. 名前付きボリュームとは?(一番下に
volumes
がいる訳)ここで先ほどの2つ目の疑問点『なんか一番下に
volumes
おる...』が解決できます。
なんとdocker-composeのvolumesにて名前を定義することによって、ボリュームに名前を付けています。実際に先ほどのdocker-composeをもう一度見てみましょう。
docker-compose.ymlversion: '3.7' services: django: restart: always build: ./django expose: - "3031" depends_on: - postgres command: bash -c "python manage.py migrate && gunicorn my_docker_project.wsgi -b 0.0.0.0:3031" volumes: - "staticdata:/opt/static/" # staticdataは一番下のvolumeで定義してるやつ! nginx: restart: always image: nginx depends_on: - django ports: - "80:80" volumes: - "./nginx/:/etc/nginx/" # docker-composeからnginxというディレクトリを相対パスにより指定 - "staticdata:/opt/apps/static/" # staticdataは一番下のvolumesで定義してるやつ! postgres: image: postgres ports: - "5432:5432" volumes: - "dbdata:/var/lib/postgresql/data" # dbdataはvolumesで定義してるやつ! environment: POSTGRES_PASSWORD: hogemojahogemoja volumes: # 名前付きボリュームを定義している dbdata: # ボリューム staticdata: # ボリューム一番下の
volumes
で名前を付けていますね〜。これによりボリュームが作成されます!
もし既に名前を付けているボリューム
をvolumes
にて指定すると、その名前の付いたボリューム
からデータを参照してきます。つまり『データを永続化している』訳ですね(/・ω・)/
そして以下のことが言えます!
- 先頭に
./
が付いていないdbdata
とstaticdata
は一番下のvolumes:
で名前を付けてから、名前付きボリュームとしてコンテナの外部に保管し、データを永続化している。- 逆に先頭に
./
が付いているnginx
は相対パスでホスト側ののマウントするディレクトリを指定して、データを永続化している。ただし名前が付いていないので、VOLUME NAME
には20文字くらいの文字列が自動で名前として付きます。なので『もう一度使える』という意味での《永続化》はしていないですね。果たして名前が付いているか
docker volume ls
コマンドにて確認します!
《サービス名_ボリューム名》となっていることが確認できました〜。(画像ではアンダーバーが途切れてます。笑)
3. 何故2回も
staticdata
を指定しているのだ...1と2からなんとなく推測してみましょう。
今までの文章から考察するとこうなるかな...
- 1的観点から記述法を見ると、名前付きボリューム(staticdata)でバックエンドとNginxにマウントをとっているのがわかる。
- 2的観点から名前付きボリュームということはデータの永続化(データを別場所にて保管)をしている。
- staticdataとdbdataを比較すると、dbdataではpostgresのvolumesの1つしか設定していなかった。
《データを別の場所にて管理》 & 《バックエンドとNginxの2つマウント取ってる。》
これらの要素からボリュームでデータを別場所で管理できることを利用して、コンテナ間のリソース共有をしている!
もしやバックエンドコンテナとNginxコンテナで静的ファイルを共有して、静的ファイルに関してだけNginxで配信するという形が取れるのでは...?
当初の僕の目的であったNginxで静的ファイルを配信することに繋がってきました
まとめ
最後まで読んでいただきありがとうございました。
Docker系は使えるツールがあまりにも多いので、本当に把握しきれないです。特にボリュームの概念をつかむのはある程度触ってからでないと難しいのかも知れません(コンテナの概念やマウントという言葉の意味など...)。ですがどこかのDocker初心者が僕のようにボリュームの概念について躓かないように、初心者である僕の目線でわかりやすく記事にさせていただきました!
間違っている点やシンプルな感想などでもございましたら、お気軽にコメントください!!
バックエンド(Django,RESTAPI)やAWS,Dockerなどの勉強していたり、機械学習にも少し手を出しているわたくしの姿を発信しているTwitterがあるので、もし良ければ...@heacet43
参考文献
- Docker、ボリューム(Volume)について真面目に調べた - Qiita [https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32]
- DjangoをDocker Composeでupしよう! - Qiita [https://qiita.com/kyhei_0727/items/e0eb4cfa46d71258f1be]
- Compose ファイル・リファレンス — Docker-docs-ja 17.06.Beta ドキュメント [http://docs.docker.jp/compose/compose-file.html#volumes-volume-driver]
- 投稿日:2020-02-08T00:15:14+09:00
ボリュームで何ができるか気づけたから解説!(docker-compose)
はじめに
Dockerって機能多すぎて、とりあえず実装して何も理解してないケースありませんか?
僕はボリュームがそのうちの1つでした...。『これから
Docker
やdocker-compose
を使い始める!』『volumes
が何をしているのか分からない...』という方には是非見て頂きたい記事となっております!これを読むことで何が分かるのか
- Dockerのボリュームとは何か分かる
- docker-composeのvolumesに何を設定するべきか分かる
docker volume ls
をした時に何故か増えてるボリューム達が何なのか分かる- DockerにてNginxを使いたい時に、コンテナ間のリソース共有実装の足がかりになる
データを永続化するとは
突然ですが、貴重なデータが含まれているデータってシンプルに消えてほしくないですよね(。・_・。)
そんな貴重なデータをDockerにてDB(データベース)コンテナとして起動させていると、docker ps
コマンドにて以下の画像のようにDBコンテナ(postgreSQL)が立ち上がっていることが確認できますよね。
ここでもし誤ってDBコンテナを消してしまう事があったら、どうなってしまうでしょうか...
DBに蓄積してきたデータが全て消えます。
ですがコンテナ管理において、デファクトスタンダードとされているDocker様がそんな状況を放置するでしょうか?いや否です。
コンテナのデータを別の場所で保管できるボリューム機能があります!
ボリュームを使えば、例えDBのコンテナを消してしまっても、データを別場所にて保管しているので、復元できるという仕組みですね(/・ω・)/
ボリューム(Data Volume)とは
こちらは僕が説明するよりコチラの記事(Docker、ボリューム(Volume)について真面目に調べた - Qiita *1)の説明が優れていると思ったので、引用させていただきます。
- ボリュームとは、データを永続化できる場所のことである。
- 外部HDDのようなイメージ。コンテナ本体にマウントして使う。
コンテナ
とボリューム
の違いについて
- コンテナ内部にデータ(ファイル)を保存しても、コンテナ破棄すると消えてしまう。
- なので、データを永続化したいときは、コンテナの外にデータを置く必要がある。
- その場所のことを、ボリュームと呼ぶ。
ボリューム
(=データを永続化できる場所) は2種類ある。
- ホストのディレクトリ(ファイル)
- ホストで ls で見えるモノ。
- Docker の リソースとしての Volume
- docker volume ls で見えるモノ。
- (本当は、これ以外にもNFSなども指定できるようだ)
- ボリュームをコンテナにマウントすることで、コンテナからアクセスできるようになる。
- あるいは
--volumes-from <コンテナ名>
とすると、指定したコンテナのマウントと同じようにマウントできる。今までの僕のdocker-composeは...?
まずは『こんな記事にわざわざ見に来ていただいて感謝』ということで、恥ずかしながらも前まで設定していた駆け出し
docker-compose
を公開します。笑docker-compose.ymlversion: "3" services: db: # データベース(つまり消えて欲しくない貴重なデータ群)が含まれているプログラム達 image: postgres environment: - POSTGRES_USER - POSTGRES_PASSWORD ports: - "5432:5432" back: # バックエンド(静的ファイル配信やmodelの定義、routing設定など)のプログラム達 build: . volumes: # 注目 - .:/code # 注目 ports: - "8000:8000" command: gunicorn config.wsgi -b 0.0.0.0:8000 # サーバー起動 depends_on: - db上記の『ボリューム(Data Volume)とは』から言うと、
volumes: - .:/codeという記述は、
ホスト側のディレクトリ(カレントディレクトリ化)
がコンテナ内(code下)
をマウントして、バックエンドのプログラムを永続化しているということになります(/・ω・)/dbにはvolumesを記述していないので、もちろん消えて欲しくない貴重なデータが含まれたデータベースは永続化していません!?!?
もう序盤で既にオチを悟った方もいるかもしれませんが(笑)、詳しくおかしな点について解説していきますね!
余談(ここはスルーしてOKです)
恐らくこれを見た経験者は『いやそこボリュームとしてデータ永続化してどないすんねん!』と言うでしょう。笑
しかも事前にvolumeの名前も定義もしていないので、docker volume ls
でボリューム一覧を出力した時にも、どれがどのボリュームなのかわからない。
やはり独学で実装していると、docker volume ls
した時に知らないボリュームが増えていくことに『違和感』を覚えることはありましたが、『おかしい』ことを確信せずに実装していたのです。なぜ勉強することになったか?
現在(2020/2/7)開発中である投票サービス《Shappar》で静的ファイルをDocker×Nginxで配信しようと思ったところ、以下の記事を見つけました。
DjangoをDocker Composeでupしよう! *2
↑上記事は要約すると『DjangoをGunicorn×Nginx×docker-composeを使ってサーバーを立ち上げよう!』というものです。そこで
docker-compose
の使用例として以下のような記述を見つけました。docker-compose.ymlversion: '3.7' services: django: restart: always build: ./django expose: - "3031" depends_on: - postgres command: bash -c "python manage.py migrate && gunicorn my_docker_project.wsgi -b 0.0.0.0:3031" volumes: - "staticdata:/opt/static/" # 3. ナンダコレ nginx: restart: always image: nginx depends_on: - django ports: - "80:80" volumes: - "./nginx/:/etc/nginx/" # 1. ナンダコレ - "staticdata:/opt/apps/static/" # 1. ナンダコレ 3. ナンダコレ postgres: image: postgres ports: - "5432:5432" volumes: - "dbdata:/var/lib/postgresql/data" environment: POSTGRES_PASSWORD: hogemojahogemoja volumes: # 2.ナンダコレ dbdata: staticdata:この記述を見て思った異変(自分の無知)の数々
./nginx/:
って...下のdbdata:
みたいにカンマスラッシュ
付けずにnginx:
←こうやって書き方統一しろよな!(※ヤバい間違いをしています。)- なんか一番下に
volumes
おる...- なぜ2回も
staticdata
を指定しているのだ...先ほどの疑問点について勉強を開始
1. ディレクトリの記述方法について
とりまdockerの公式docs *3に飛びます。すると以下の記述がありました。
docker-compose.ymlvolumes: # 1.パスを指定したら、Engine はボリュームを作成 - /var/lib/mysql # 2.絶対パスを指定しての割り当て - /opt/data:/var/lib/mysql # 3.ホスト上のパスを指定する時、Compose ファイルからのパスを指定 - ./cache:/tmp/cache # 4.ユーザの相対パスを使用 - ~/configs:/etc/configs/:ro # 5.名前付きボリューム(Named volume) - datavolume:/var/lib/mysq記述によって動作が全く違う件
引用してきた上記の
docker-compose
から、僕が疑問に思った記述方法は③と⑤に当てはまります。結論から言うと、
./nginx/:/etc/nginx/
とnginx:/etc/nginx/
とでは、プログラムの実行内容が全然違います。
./nginx/:
docker-compose.yml
が存在しているディレクトリから、相対パスによってマウントする側の指定先としてホスト側のディレクトリ
の指定を行います。nginx:
この書き方をすると、マウントする側の指定先として nginx
という名前付きボリューム
を探します。マウントする側の指定方法として、
./nginx/:
はカレントディレクトリから〜、対してnginx:
は名前付きボリューム
ありきで〜、というように方法が全く異なっていますね。はて?名前付きボリュームですか。
2. 名前付きボリュームとは?(一番下に
volumes
がいる訳)ここで先ほどの2つ目の疑問点『なんか一番下に
volumes
おる...』が解決できます。
なんとdocker-composeのvolumesにて名前を定義することによって、ボリュームに名前を付けています。実際に先ほどのdocker-composeをもう一度見てみましょう。
docker-compose.ymlversion: '3.7' services: django: restart: always build: ./django expose: - "3031" depends_on: - postgres command: bash -c "python manage.py migrate && gunicorn my_docker_project.wsgi -b 0.0.0.0:3031" volumes: - "staticdata:/opt/static/" # staticdataは一番下のvolumeで定義してるやつ! nginx: restart: always image: nginx depends_on: - django ports: - "80:80" volumes: - "./nginx/:/etc/nginx/" # docker-composeからnginxというディレクトリを相対パスにより指定 - "staticdata:/opt/apps/static/" # staticdataは一番下のvolumesで定義してるやつ! postgres: image: postgres ports: - "5432:5432" volumes: - "dbdata:/var/lib/postgresql/data" # dbdataはvolumesで定義してるやつ! environment: POSTGRES_PASSWORD: hogemojahogemoja volumes: # 名前付きボリュームを定義している dbdata: # ボリューム staticdata: # ボリューム一番下の
volumes
で名前を付けていますね〜。これによりボリュームが作成されます!
もし既に名前を付けているボリューム
をvolumes
にて指定すると、その名前の付いたボリューム
からデータを参照してきます。つまり『データを永続化している』訳ですね(/・ω・)/
そして以下のことが言えます!
- 先頭に
./
が付いていないdbdata
とstaticdata
は一番下のvolumes:
で名前を付けてから、名前付きボリュームとしてコンテナの外部に保管し、データを永続化している。- 逆に先頭に
./
が付いているnginx
は相対パスでホスト側ののマウントするディレクトリを指定しているだけ。つまりデータを永続化してない。果たして名前が付いているか
docker volume ls
コマンドにて確認します!
《サービス名_ボリューム名》となっていることが確認できました〜。(画像ではアンダーバーが途切れてます。笑)
3. 何故2回も
staticdata
を指定しているのだ...1と2からなんとなく推測してみましょう。
今までの文章から考察するとこうなるかな...
- 1的観点から記述法を見ると、名前付きボリューム(staticdata)でバックエンドとNginxにマウントをとっているのがわかる。
- 2的観点から名前付きボリュームということはデータの永続化(データを別場所にて保管)をしている。
- staticdataとdbdataを比較すると、dbdataではpostgresのvolumesの1つしか設定していなかった。
《データを別の場所にて管理》 & 《バックエンドとNginxの2つマウント取ってる。》
これらの要素からボリュームでデータを別場所で管理できることを利用して、コンテナ間のリソース共有をしている!
もしやバックエンドコンテナとNginxコンテナで静的ファイルを共有して、静的ファイルに関してだけNginxで配信するという形が取れるのでは...?
当初の僕の目的であったNginxで静的ファイルを配信することに繋がってきました
まとめ
最後まで読んでいただきありがとうございました。
Docker系は使えるツールがあまりにも多いので、本当に把握しきれないです。特にボリュームの概念をつかむのはある程度触ってからでないと難しいのかも知れません(コンテナの概念やマウントという言葉の意味など...)。ですがどこかのDocker初心者が僕のようにボリュームの概念について躓かないように、初心者である僕の目線でわかりやすく記事にさせていただきました!
間違っている点やシンプルな感想などでもございましたら、お気軽にコメントください!!
バックエンド(Django,RESTAPI)やAWS,Dockerなどの勉強していたり、機械学習にも少し手を出しているわたくしの姿を発信しているTwitterがあるので、もし良ければ...@heacet43
参考文献
- Docker、ボリューム(Volume)について真面目に調べた - Qiita [https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32]
- DjangoをDocker Composeでupしよう! - Qiita [https://qiita.com/kyhei_0727/items/e0eb4cfa46d71258f1be]
- Compose ファイル・リファレンス — Docker-docs-ja 17.06.Beta ドキュメント [http://docs.docker.jp/compose/compose-file.html#volumes-volume-driver]