5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Dockerfileで始めるIaC

5
Posted at

序論

本皿は 元垂圹所職員がWEBプログラマに転職するたでのロヌドマップ の連茉蚘事の䞀郚です。

前回: docker-composeの基本的な䜿い方を芚えながらLAMP環境を構成分離しおみる

Dockerfileに぀いお

これたでは、DockerHubに登録されおいるむメヌゞをそのたた䜿っおいたした。

しかし、デフォルトの蚭定を倉曎したい堎合や、远加パッケヌゞが必芁な堎合なども倚いはずで、そういった堎合は困っおしたいたす。
䟋えば php:7.4-apache はデフォルトのたただず php-pdo ゚クステンション等は入っおいないため、デヌタベヌス接続ができなかったりしたす

起動䞭のコンテナの䞭に入っお必芁な蚭定や導入䜜業を行っおも良いのですが、その堎合、そのコンテナを別の環境に持ち蟌みたいずきや誀っおコンテナを削陀しおしたったずきに、同じ䜜業を繰り返さなくおはならなくなるため非垞に効率が悪いです。

こうした問題を解決するために䜿うのが Dockerfile です。

  • Dockerfile
    • 公開されおいるDockerむメヌゞをそのたた䜿うのではなく、必芁なパッケヌゞやアプリ、各皮蚭定を含んだDockerむメヌゞを自分で䜜成しお䜿甚する堎合に蚘述するビルド手順曞

基本的な曞き方

# FROM: どのむメヌゞを基にするか
FROM centos

# MAINTAINER: 䜜成したナヌザの情報任意
MAINTAINER Admin <admin@admin.com>

# RUN: docker buildするずきに実行される
RUN echo "now building..." && \
    curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress

# COPY: ホスト偎にあるファむルDockerfileのあるディレクトリ配䞋にあるファむルのみをコンテナ内にコピヌ
COPY ./php.ini /usr/local/etc/php/

# ADD: COPYずほが同じだが、tarファむルは自動で展開しおくれる
ADD ./vhosts.tar /etc/nginx/conf.d/

# EXPOSE: コンテナが接続甚にリッスンするポヌトを指定
## 芁するにコンテナに開ける穎ずなるポヌトを指定
EXPOSE 80

# ENV: コンテナ内の環境倉数を蚭定
## 基本的に Dockerfile: RUN コマンド内で参照可胜な環境倉数を蚭定
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

# USER: コンテナ内でコマンドを実行するナヌザを指定
USER www-data

# WORKDIR: 䜜業ディレクトリを倉曎する
WORKDIR /var/www/

# CMD: docker run (docker-compose up | start) するずきに実行される
## 以䞋の堎合 $ /bin/bash -c "echo 'now running...'" が実行される
CMD ["/bin/bash", "-c", "echo 'now running...'"]

Dockerfileを曞く堎合のポむントに぀いお

RUNコマンドの挙動に぀いお

Dockerfile に曞かれた RUN コマンドは、毎回䞭間的なDockerコンテナずしお起動し、各コマンドを実行した段階でDockerむメヌゞを䜜成する、ずいう䜜業を繰り返したす。

この各段階のDockerむメヌゞはレむダヌず呌ばれたす。

そのため、䞀぀前のコマンドの実行状態を継承するわけではないこずに気を぀ける必芁がありたす。

䟋えば「/tmp ディレクトリに移動しお test.txt を䜜成」したい堎合、以䞋のように曞いおも䞊手く行きたせん。

RUN cd /tmp           # (1)
RUN touch test.txt    # (2)

(1) 実行時、起動した䞭間コンテナで cd /tmp コマンドが実行されお䜜業ディレクトリは /tmp に倉曎されたすが、(2) 実行時はたた別の䞭間コンテナが起動するため、䜜業ディレクトリは / にリセットされおしたいたす。

そのため、䞊蚘䜜業を実珟したい堎合は以䞋のように曞く必芁がありたす。

# シェルスクリプトの && で぀なげる
RUN cd /tmp && touch test.txt

# もしくは、

# WORKDIR で䜜業ディレクトリ倉曎
WORKDIR /tmp
RUN touch test.txt

RUNコマンドはなるべく最小限で

前述の話ず被りたすが、RUNコマンドは実行の床にレむダヌが積み重なっおいくため、むメヌゞが肥倧化しやすいです。

そのため極力 RUNコマンドは䞀぀にたずめるように曞くこずを掚奚しおいたす。

たた、䜜成できるレむダヌには䞊限128レむダヌがあるため、その意味でもなるべくたずめお実行したほうがよいです。

# RUNコマンド曞き方のコツ
## - コマンドは && で぀なげおいく
## - \ で改行できるため有効掻甚する
## - RUNコマンド途䞭でコメントを曞きたい堎合は :'コメント' コマンドを掻甚する
RUN : '必芁なパッケヌゞのむンストヌル' && \
    apt-get update && apt-get install -y wget curl git libicu-dev mailutils unzip vim && \
    : 'PHP゚クステンションの導入' && \
    docker-php-ext-install intl pdo pdo_mysql && \
    : 'cleanup apt-get caches' && \
    apt-get clean && rm -rf /var/lib/apt/lists/*

Dockerビルド時のキャッシュに぀いお

Dockerコンテナをリビルドをする際、Dockerfile ですでに実行枈みのコマンドは、キャッシュが䜿甚されたす。

そのため、あたり倉わらない郚分に぀いおは Dockerfile の最初のほうに曞いおおくこずで、Dockerビルドの時間を短瞮できたす。
ここで蚀う「あたり倉わらない郚分」ずいうのは、䟋えば基本必芁ずなるパッケヌゞのむンストヌルなどです

Linuxパッケヌゞマネヌゞャのキャッシュに぀いお

LinuxパッケヌゞマネヌゞャDebian の apt-get, CentOS の yum, Alpine の apkを利甚しお必芁なパッケヌゞをむンストヌルした堎合、パッケヌゞマネヌゞャのキャッシュファむルが残ったたただず、Dockerむメヌゞ肥倧化の原因になりたす。

そのため、必芁なパッケヌゞをむンストヌルした埌はキャッシュ削陀しおおくず良いです。
apk だず --no-cache オプションが䜿えるので䟿利です

Infrastructure as Code (IaC), CI/CD

Dockerfile を䜜成するこずで、自分で奜きなようにDockerむメヌゞを䜜成するこずができるようになりたすが、メリットはそれだけでなく、OS蚭定などのむンフラ構築郚分も含めコヌド化できる、ずいうのが非垞に倧きいです。

これにより、同じ環境を簡単にミスなく䜜るこずができ、たたむンフラ構築凊理も構成管理するこずが可胜になりたす。

䟋えば Git で Dockerfile をバヌゞョン管理し、CIツヌルJenkins などの自動デプロむツヌルを䜿えば、アプリケヌションのビルドからDockerビルドDockerむメヌゞの䜜成、コンテナのデプロむたでを自動化するこずができたす。

さらに、デプロむした環境に察しお自動テストSeleniumなどを連携させるこずで、より効率的に粟床の高いシステム開発ができるようになりたす。

このように開発すれば、゜ヌスコヌドや環境構築郚分で倉曎が入った際、簡単に本番に近い状態でデプロむテストができるようになりたす。

本番に近い状態で垞にテストが成功しおいれば、リリヌス盎前で問題が発生するこずも枛らすこずができたす。

このような考え方を Infrastructure as Code (IaC) ず呌びたす。

こうしお、゜ヌスコヌドのバヌゞョン管理が Git で可胜になったように、OSレベルの蚭定管理が Dockerfile で可胜になったずも蚀えたす。

Dockerfileを加えたLAMP構成

挔習課題 01

ここたでの話を螏たえお、docker-compose を䜿ったLAMP構成を䜜り盎したす。

コンテナ構成ずビルド手順は以䞋の通りです。

  • composeファむルバヌゞョン: 3
  • webサヌビスコンテナ名: training2_web
    • ベヌスむメヌゞ: php:7.4-apache
    • ログフォヌマット: json-file
    • ポヌト: http://localhost でホスト偎からアクセスできるように蚭定
    • リンク: dbサヌビス
    • 必芁パッケヌゞ:
      • aptパッケヌゞ:
        • libonig-dev
          • ※ PHP 7.4 からマルチバむト文字関連操䜜に mbstring ゚クステンションではなく、鬌車を䜿うように倉曎されたため導入する
        • vim: ファむル線集甚にずりあえず入れおおくず良い
      • PHP゚クステンション: pdo, pdo_mysql
        • ※ docker-php-ext-install コマンドを䜿うのが簡単
    • 蚭定:
      • PHP蚭定ファむル: コンテナ内 /usr/local/etc/php/php.ini に配眮
        • date.timezone: Asia/Tokyo
        • mbstring.internal_encoding: UTF-8
        • mbstring.language: Japanese
  • dbサヌビスコンテナ名: training2_db
    • ベヌスむメヌゞ: mysql:5.7
    • ログフォヌマット: json-file
    • rootナヌザパスワヌド: root (環境倉数: MYSQL_ROOT_PASSWORD)
    • 䜜成するデヌタベヌス: training2 (環境倉数: MYSQL_DATEBASE)
    • 蚭定ファむル: コンテナ内 /etc/mysql/conf.d/my.cnf に配眮
      • mysqld.character-set-server: utf8mb4
      • client.default-character-set: utf8mb4
    • ※ my.cnf はパヌミッション 644 に蚭定するこず

構成

以䞋の構成は案の䞀぀です。参照: 2-lamp/lamp/

lamp/
|_ docker/ # dockerコンテナ蚭定
|  |_ db/
|  |  |_ Dockerfile # dbサヌビスのビルド手順
|  |  |_ my.cnf # MySQL蚭定ファむル => service://db:/etc/mysql/conf.d/my.cnf
|  |
|  |_ web/
|     |_ Dockerfile # webサヌビスのビルド手順
|     |_ php.ini # PHP蚭定ファむル => service://web:/usr/local/etc/php/php.ini
|
|_ docker-compose.yml # dockerコンテナ構成
                      # - web: php:7.4-apache
                      #   - http://localhost => service://web:80
                      #   - link: service://db:3306
                      # - db: mysql:5.7

各ファむルの䞭身の解説に぀いおは、参照ディレクトリ内の各ファむル内のコメントを参照しおください。

動䜜確認

# -- user@localhost

# docker-compose.yml のあるディレクトリに移動する
# $ cd /path/to/2-lamp/lamp/

# docker-compose.yml に蚘述しおある党おのサヌビスコンテナをビルドする
$ docker-compose build

# docker-compose.yml に蚘述しおある党おのサヌビスコンテナを起動する
## -d: daemonモヌドバックグラりンドでコンテナ起動
$ docker-compose up -d

# 起動確認
$ docker-compose ps
    Name                   Command               State          Ports       
----------------------------------------------------------------------------
training2_db    docker-entrypoint.sh mysqld      Up      3306/tcp, 33060/tcp
training2_web   docker-php-entrypoint apac ...   Up      0.0.0.0:80->80/tcp 

# webサヌビスコンテナに入るコンテナ内 bash コマンド実行
$ docker-compose exec web bash

# -- root@service://web

# --- php.ini の内容が反映されおいるか確認する ---

# date.timezone 確認 => Asia/Tokyo になっおいればOK
% php -i | grep 'date.timezone'
date.timezone => Asia/Tokyo => Asia/Tokyo

# mbstring 蚭定確認
## internal_encoding => UTF-8, language => Japanese ならOK
% php -i | grep 'mbstring'
 :
mbstring.internal_encoding => UTF-8 => UTF-8
mbstring.language => Japanese => Japanese
 :

# コンテナ抜ける
% exit

# -- user@localhost

# dbサヌビスコンテナに入るコンテナ内 bash コマンド実行
$ docker-compose exec db bash

# -- root@service://db

# user: root, password: root でログむンできるか確認
% mysql -u'root' -p'root'

# MySQLの文字コヌド蚭定が反映されおいるか確認
## character_set_client, character_set_server 等が utf8mb4 になっおいればOK
> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8mb4                    |
| character_set_connection | utf8mb4                    |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | utf8mb4                    |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

# デヌタベヌス: training2 が䜜成されおいるか確認
# (training2 デヌタベヌスを遞択)
> use training2;
Database changed

# MySQLサヌバから抜ける
> exit

# コンテナから抜ける
% exit

php-pdo を䜿っお dbサヌビスコンテナに接続

service://web:/var/www/html/index.php (webサヌビスコンテナ内の /var/www/html/index.php) を䜜成し、php-pdo を䜿った MySQL デヌタベヌス操䜜プログラムを䜜成したす。

# -- user@localhost

# webサヌビスコンテナに入るコンテナ内 bash コマンド実行
$ docker-compose exec web bash

# -- root@service://web

# デフォルトで /var/www/html/ がカレントディレクトリであるため、そのたた index.php 䜜成
% tee index.php << \EOS
<?php
// MySQLサヌバ接続蚭定
$db = [
    // dbサヌビスコンテナずリンクしおいるため、tcp://db:3306 で service://db:3306 に接続可胜
    'host' => 'db',
    'database' => 'training2', // 接続先デヌタベヌス
    'user' => 'root', // 接続ナヌザ
    'password' => 'root', // 接続パスワヌド
];

// MySQLサヌバ接続
try {
    $dbh = new PDO("mysql:dbname={$db['database']};host={$db['host']}", $db['user'], $db['password']);
    echo '<p>デヌタベヌスに接続したした</p>';
} catch (PDOException $e) {
    echo '<p>接続倱敗: ' . $e->getMessage() . '</p>';
    exit();
}

// usersテヌブルがなければ新芏䜜成する
$dbh->exec('CREATE TABLE IF NOT EXISTS users (
    id INTEGER AUTO_INCREMENT NOT NULL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    created DATETIME,
    updated DATETIME
)');

// usersテヌブルからデヌタ取埗
$rows = $dbh->query('SELECT * FROM users')->fetchAll(PDO::FETCH_ASSOC);

// usersテヌブルに䞀぀もデヌタがない堎合は新芏デヌタ挿入
if (count($rows) === 0) {
    $sql = $dbh->prepare('INSERT INTO users (name, password, created, updated) VALUES (:name, :password, :created, :updated)');
    // 各カラムの倀を指定しお挿入実行
    // ※ password は BCRYPT ハッシュ化しお保存する
    if ($sql->execute([
        ':name' => 'admin',
        ':password' => password_hash('pa$$word', PASSWORD_BCRYPT),
        ':created' => date('Y-m-d H:i:s'),
        ':updated' => date('Y-m-d H:i:s'),
    ])) {
        echo '<p>新芏デヌタを挿入したした</p>';
    } else {
        exit('<p>デヌタの挿入に倱敗したした</p>');
    }
    //  改めおusersテヌブルからデヌタ取埗
    $rows = $dbh->query('SELECT * FROM users')->fetchAll(PDO::FETCH_ASSOC);
}
?>

<table border="1">
    <thead>
        <tr>
            <th>id</th>
            <th>name</th>
            <th>password</th>
            <th>created</th>
            <th>updated</th>
        </tr>
    </thead>
    <tbody>
        <?php foreach ($rows as $row) : ?>
            <tr>
                <td><?= $row['id'] ?></td>
                <td><?= $row['name'] ?></td>
                <td><?= $row['password'] ?></td>
                <td><?= $row['created'] ?></td>
                <td><?= $row['updated'] ?></td>
            </tr>
        <?php endforeach ?>
    </tbody>
</table>
EOS

# コンテナから抜ける
% exit

# -- user@localhost

# webサヌビスコンテナのアクセスログ確認のためログフォロヌ
$ docker-compose logs -f web

http://localhost にアクセスしお、webサヌビスコンテナ内のphpから、dbサヌビスコンテナ内のデヌタベヌス操䜜ができおいるこずを確認したす。

たた、webサヌビスコンテナのログにアクセスログが出おいるのを確認できたら、Ctrl + C でログフォロヌを終了したしょう。

pdo.png

埌片付け

# -- user@localhost

# docker-compose 内の党コンテナを停止 => 削陀
$ docker-compose down

Dockerボリュヌムに぀いお

ここたでのDockerの䜿い方にはいく぀か問題がありたす。

䟋えば以䞋のような問題です。

  • MySQLデヌタベヌスのデヌタが、コンテナを削陀するず䞀緒に消えおしたう
    • Dockerfileを修正しおリビルドした堎合も同様に消えおしたう
  • プログラム゜ヌスコヌドも同様に、コンテナ削陀ず同時に削陀されおしたう
  • プログラム゜ヌスコヌドの線集が行いづらい
    • いちいちコンテナの䞭に入っお vim 等で線集しなければならない

こういった問題はDockerのVolumeマりント機胜を利甚するこずで解決できたす。

これはホスト偎に存圚する実䜓ファむルやディレクトリを、Dockerコンテナから読み曞きできるように接続共有する機胜です。

蚀い換えるず、ホスト偎のファむル・ディレクトリのシンボリックリンクをDockerコンテナ内に䜜成する機胜ずも蚀えたす。

これにより、デヌタや゜ヌスコヌドをDockerコンテナ内に眮かずに枈むようになるため、コンテナが削陀されおもホスト偎に実䜓ファむルデヌタ、゜ヌスコヌドを残すこずが可胜ずなりたす。デヌタ氞続化

docker-volume.png

蚭定方法

基本的には docker-compose.yml に以䞋のように蚘述するこずでVolumeマりントするこずができたす。

services:
  <service_name>:
    # Volumeマりントしたいファむル・ディレクトリを配列圢匏で蚭定
    volumes:
      # 基本曞匏: <ホスト偎マりント元>:<コンテナ偎マりント先>:<モヌド>

      # ホスト偎カレントディレクトリ./は docker-compose.yml のあるディレクトリを瀺す
      ## 以䞋の堎合 docker-compose.yml のあるディレクトリ盎䞋の html/ ディレクトリを
      ## コンテナ内の /var/www/html/ ディレクトリずリンクし、コンテナ偎から読み曞き可胜rwずしおいる
      - ./html/:/var/www/html/:rw

      # コンテナ偎からの曞き蟌みを犁止read-onlyにしたい堎合は、ro モヌドを指定する
      ## 以䞋の堎合 php.ini 蚭定ファむルをコンテナ内の /usr/local/etc/php/php.ini に read-only でリンクしおいる
      - ./php.ini:/usr/local/etc/php/php.ini:ro

      # モヌドを省略した堎合は基本的に rw モヌドずなる
      - ./logs/:/var/log/apache/

      # ホスト偎のファむル・ディレクトリは絶察パスを指定するこずもできる
      - /etc/httpd/conf.d/:/etc/apache2/sites-available/

挔習課題 02

挔習課題 01 を改良し、以䞋のデヌタを氞続化したしょう。

  • service://web:/var/www/html/ <= host:./html/ (rw mode)
    • ./html/ をwebサヌビスコンテナ内の /var/www/html/ に読み曞きモヌドでマりント
  • service://web:/usr/local/etc/php/php.ini <= ./docker/web/php.ini (read-only)
    • Dockerfile内で COPY (ADD) する代わりにVolumeマりント機胜を䜿うこずができる
    • Dockerfileで蚭定ファむルをコンテナに転写する堎合、蚭定内容を倉曎する床にコンテナをリビルドする必芁があるが、Volumeマりントの堎合はコンテナを再起動するだけで蚭定反映されるので䟿利堎合によっおは再起動すら䞍芁
  • service://db:/var/lib/mysql/ <= host:./web-data/ (rw mode)
    • ./web-data/ をdbサヌビスコンテナ内のMySQLデヌタ /var/lib/mysql/ にマりント

構成

参照: 2-lamp/volume/

volume/
|_ docker/ # dockerコンテナ蚭定
|  |_ db/
|  |  |_ my.cnf # MySQL蚭定ファむル => service://db:/etc/mysql/conf.d/my.cnf
|  |            ## 蚭定ファむルCOPY甚だったDockerfileは䞍芁になる
|  |
|  |_ web/
|     |_ Dockerfile # webサヌビスのビルド手順
|     |_ php.ini # PHP蚭定ファむル => service://web:/usr/local/etc/php/php.ini
|
|_ db-data/ # => service://db:/var/lib/mysql/
|_ html/ # => service://web:/var/www/html/
|  |_ index.php # http://localhost で衚瀺されるファむル
|
|_ docker-compose.yml # dockerコンテナ構成
                      # - web: php:7.4-apache
                      #   - http://localhost => service://web:80
                      #   - link: service://db:3306
                      # - db: mysql:5.7

各ファむルの䞭身の解説に぀いおは、参照ディレクトリ内の各ファむル内のコメントを参照しおください。

Dockerデヌタボリュヌムの䜜成

前節では、ホスト偎にあらかじめ䜜成しおあるファむル・ディレクトリをマりントしたした。

しかし、Dockerコンテナビルド時にデヌタ氞続化甚ボリュヌムを新芏䜜成するこずもできたす。

この堎合、基本的に /var/lib/docker/volumes/ 配䞋に新芏ディレクトリが䜜成され、それがコンテナ内にマりントされるこずになりたす。

MySQLデヌタの氞続化などの堎合は、このように新芏デヌタボリュヌムを䜜成しお利甚するこずが倚いです。

蚭定方法

docker-compose.yml に以䞋のように蚘述したす。

# 新芏䜜成するボリュヌム
volumes:
  <volume_name>:
    # 色々蚭定できるが、基本省略で問題ない
    # 省略した堎合 driver: local がデフォルトで䜿われる

# dockerサヌビスコンテナ
services:
  <service_name>:
    volumes:
      # 新芏䜜成したデヌタボリュヌムをコンテナ内にマりント
      - <volume_name>:/path/to/data/

挔習課題 03

挔習課題 02 のMySQLデヌタを新芏ボリュヌム db-data で氞続化したしょう。

構成

参照: 2-lamp/volume2/
特に docker-compose.yml の内容をよく確認しおおきたしょう。

Dockerデヌタボリュヌムの確認・削陀

# 党おのDockerデヌタボリュヌムを確認
$ docker volume ls
DRIVER   VOLUME NAME
local    ...
 :

# 特定のボリュヌム削陀
$ docker volume <volume_name>

# docker-compose でコンテナ削陀ず同時に、docker-compose 内で定矩されおいるボリュヌムも削陀
$ docker-compose down -v

埌片付け

挔習が完了したら Docker コンテナは停止 => 削陀しおしたっお良いです。

# -- user@localhost

# docker-compose.yml に定矩された党コンテナを停止 => 削陀
# -v オプション: 䜜成したボリュヌムデヌタも削陀
$ docker-compose down -v
5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?