カテゴリー: Git

Bitbucket PipelinesでDocker Composeプロジェクトをインテグレーションテストする

はじめまして。小國です。

今回は、Docker Compose で構築されたプロジェクトを、Bitbucket Pipelines を使ってインテグレーションテストする方法をご紹介したいと思います。

はじめに

シーズのプロジェクトの開発環境・手法は、主に以下のような構成となっています。

  • VCS に Git を使い、Bitbucket にホスティングしている
  • 各プロジェクトは Docker Compose を使い、ローカル環境を構築し、開発を行っている
  • PHPUnit などを使って、テストケースを書いている

Bitbucket Pipelines で Docker Compose を使うには

Bitbucket には Pipelines という CI/CD サービスがあり、Docker を使ったテストが行なえます。

ですが、Pipelines で Docker Compose を使うためには、自身で Docker Compose バイナリを作成しなければなりません。

参考: https://ja.confluence.atlassian.com/bitbucket/run-docker-commands-in-bitbucket-pipelines-879254331.html

今回は、Docker Compose バイナリの作成・公開し、サンプルプロジェクトを使って、Pipelines で PHPUnit のテストを実行するまでを行います。

やってみましょう

主な流れは以下のようになります。

  1. Docker Compose バイナリの作成と、作成したバイナリを Docker Hub に公開
  2. サンプルプロジェクトの作成
  3. bitbucket-pipelines.yml の作成
  4. Bitbucket で Pipelines の有効化

Docker Compose バイナリの作成と、作成したバイナリを Docker Hub に公開

なお、https://hub.docker.com/r/seedsstd/seeds_bitbucket_pipelines にほぼ同様のイメージを公開していますので、こちらを使用する方は、このステップは不要です。

  • Docker Compose バイナリの作成
$ mkdir seeds_bitbucket_pipelines && cd seeds_bitbucket_pipelines
$ cat <<EOF > Dockerfile
FROM docker:stable
# Add python pip and bash
RUN apk add --no-cache py-pip
RUN apk add --no-cache python-dev libffi-dev openssl-dev gcc libc-dev make
RUN apk add --no-cache bash
# Install docker-compose via pip
RUN pip install --no-cache-dir docker-compose
EOF
  • 作成したバイナリを Docker Hub に公開
docker build -t <YOUR_ACCOUNT>/seeds_bitbucket_pipelines:stable .
docker push <YOUR_ACCOUNT>/seeds_bitbucket_pipelines:stable

<YOUR_ACCOUNT> には、自身の Docker Hub アカウント、またはオーガニゼーションを指定してください。

docker build -t seedsstd/seeds_bitbucket_pipelines:stable .
docker push seedsstd/seeds_bitbucket_pipelines:stable

サンプルプロジェクトの作成

サンプルプロジェクトを作成ます。ファイル構成、内容は以下のとおりです。

$ tree
.
├── composer.json
├── composer.lock
├── composer.phar
├── docker-compose.yml
├── php-apache
│   └── Dockerfile
└── tests
└── SampleTest.php
2 directories, 6 files
  • composer.json
{
"name": "seeds-std/blog_bitbucket_pipelines",
"authors": [
{
"name": "SEEDS Co.,Ltd",
"email": "info@seeds-std.co.jp"
}
],
"require": {},
"require-dev": {
"phpunit/phpunit": "^8.3"
}
}
  • docker-compose.yml
version: "3"
services:
web:
build: php-apache # php7.2-apache に git が入っていなかったため作成
volumes:
- ./:/var/www/html
  • php-apache/Dockerfile
FROM php:7.2-apache
RUN apt-get update -y && apt-get install -y git
  • tests/SampleTest.php
<?php
class SampleTest extends \PHPUnit\Framework\TestCase
{
/**
     * @return void
     */
public function testTrueIsTrue()
{
$this->assertTrue(true);
}
}

ここでのポイントは docker-compose run --rm web bash -c "php composer.phar install && vendor/bin/phpunit tests/SampleTest.php" というような形で、ホスト側から PHPUnit のテストが実行できることです。

ためしに、実行してテストが通ることを確認しましょう。

$ docker-compose run web /bin/bash -c "php composer.phar install && vendor/bin/phpunit tests/SampleTest.php"
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Nothing to install or update
Generating autoload files
PHPUnit 8.3.5 by Sebastian Bergmann and contributors.
.                                                                   1 / 1 (100%)
Time: 545 ms, Memory: 4.00 MB
OK (1 test, 1 assertion)

良さそうですね。

bitbucket-pipelines.yml の作成

以下のような bitbucket-pipelines.yml を作成し、リポジトリの直下に含めます。

内容は、上記で作成した Docker Compose バイナリを使い、そのホストからコンテナを起動しテストする内容になっています。

image: seedsstd/seeds_bitbucket_pipelines:stable
options:
docker: true
default_script: &default_script
- docker-compose run --rm web /bin/bash -c "php composer.phar install && vendor/bin/phpunit tests/SampleTest.php"
- docker-compose down
pipelines:
default:
- step:
script: *default_script

Pipelines の有効化

最後に、Bitbucket の画面から Pipelines を有効化します。

f:id:seeds-std:20190927100459p:plain

Pipelines を有効化すると、以下のように bitbucket-pipelines.yml で指定したテストが実行されます。

f:id:seeds-std:20190927100819p:plain

テストが全て正常に終わり、以下のようになればおkです。

f:id:seeds-std:20190927101038p:plain

最後に

Bitbucket Pipelines で Docker Compose を使用したプロジェクトのテストを実行することができました。

Laravelを学ぶ為、DockerでLaravelを動かせる環境を構築した

こんにちは、西山です。

今回からは麻雀に負けずともブログ記事を書こうと思います。

エンジニア35歳定年説を気にせず
PHPフレームワークとして有名なLaravelを勉強し始めましたので
学んだ事や経験した事を記載していきます。

会社ではDockerを立ち上げるだけで完全に自動化され
ファイルの修正が必要なく、Laravelが動作するDockerリポジトリが存在します。

それとは別に、自分で一からDockerの開発環境を作成してみました。

便利な物を効率よく使うのも重要ですが
学習の為、自分で作成したDocker環境にLaravelをインストールし
シンプルな内容のリポジトリを作成しました。

github.com

この作成過程や実際に作成したリポジトリの使い方を元に話を進めます。

尚、開発環境はMacで、Dockerは 「Docker Desktop for Mac」 を使用しました。

docs.docker.com

※Windowsでは、「Docker Toolbox」を使用しDockerの環境を用意しました。

■1. Laravelの学習

リポジトリを作成するにあたり、まずは下記の2つを取り組みました。

ドットインストール 「Laravel 5.5入門」
書籍 「PHPフレームワーク Laravel入門」

ドットインストールは短い動画が複数あり取り組みやすく分かりやすいですが
細かく気になった点が省かれていると感じました。
その後で、書籍で丁寧に一通り説明されているのを読み、理解が進みました。

全体の流れをドットインストールで学んでからだったので、書籍の細かい点も分かりやすく感じました。

Laravelはインストールも簡単ですし、ベースのファイルを作成する為の便利なコマンドも多く用意されています。

■2. リポジトリの作成「DockerへのLaravelのインストール」

元々PHPが動作するシンプルなDockerを作成していまして
そこにLaravelのインストールとプロジェクト作成を行い、今回のリポジトリを作成しました。

作業の流れを記載します。

Dockerのコンテナを作成・起動

docker-compose up -d

「web」という名前のコンテナを私は用意しています。

Webサーバーのコンテナに入る

docker-compose exec web bash

Webサーバーに入って、Laravelをインストールします。
まずはComposerのインストールが必要です

https://getcomposer.org/download/

下記の記載があるので、それぞれ1行ずつコマンドを叩き実行します

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

ここまで実行すると下記のファイルが作成されています。
composer.phar

ここで、ComposerからLaravelをインストールします。
laravel_appという名前でプロジェクトを作ります。

プロジェクト作成

php composer.phar create-project --prefer-dist laravel/laravel laravel_app

インストールが完了しましたら、プロジェクトのディレクトリに移動しLaravelのバージョンを確認します。

ディレクトリ移動

cd laravel_app

Laravelのバージョン確認

php artisan --version

この artisan のコマンドはモデル、コントローラー、マイグレーション等の様々なベースファイルの作成ができたりなど
Laravel開発に置いて、非常に便利なコマンドです。
artisan は職人という意味なので、指示を出して使いこなすエンジニアは親方ですね。

下記のようにバージョンが表示されればOKです。

Laravel Framework 5.8.34

laravel

親方デビューです。

追加されたLaravelのファイルを git add して今回のリポジトリが作成できました。

■3. リポジトリの使い方「Laravelのリポジトリを git clone して動かす時の注意点」

しかし、別PCに git clone してdockerを立ち上げて動かそうとした所、動きませんでした。
別の現場では、すんなり親方になれませんでした。

エラーメッセージ

Warning:  require(/app/laravel_app/public/../vendor/autoload.php): failed to open stream: No such file or directory in /app/laravel_app/public/index.php on line 24
Fatal error:  require(): Failed opening required '/app/laravel_app/public/../vendor/autoload.php' (include_path='.:/usr/local/lib/php') in /app/laravel_app/public/index.php on line 24

先ほど自分で名前を決めて作成したLaravelのプロジェクトのディレクトリ「laravel_app」
下記にvendorディレクトリが存在していませんでした。

/laravel_app/vendor

artisanコマンドでプロジェクトを作った時には存在しましたが
vendorディレクトリが無いのでインストール

■【現在はDockerのwebサーバーのディレクトリ「laravel_app」にいる状態】

※ /composer.phar に「composer.phar」は存在します。

インストール

php ../composer.phar install

vendorディレクトリが作成されましたが、500エラーと表示されます。

500 Server Error

【Laravel】の環境変数設定ファイル「.env」が作成されていなかったので作成します。
Gitで管理されない状態になっていました。

/laravel_app/.envを作成

cp .env.example .env

Dockerで開発していますので、Dockerのデータベースの設定を確認します。

/docker-compose.yml の設定を確認

version: '3'
services:
web:
build: ./docker/web/
depends_on:
- db
volumes:
- ./:/app
- ./docker/web/php.ini:/usr/local/etc/php/php.ini
- ./docker/web/000-default.conf:/etc/apache2/sites-enabled/000-default.conf
working_dir: /app
ports:
- ${WEB_PORT}:80
db:
build: ./docker/db/
volumes:
- ./docker/db/mysql:/var/lib/mysql
- ./docker/db/init:/docker-entrypoint-initdb.d
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
ports:
- ${DB_PORT}:3306

上記の {MYSQL_ROOT_PASSWORD} の記載は
【Docker】の環境変数の設定ファイル「.env」で管理しています。
※Laravelの環境変数の設定ファイルとは別ファイルで、リポジトリ直下に存在します。

Dockerの .env 場所

/.env

/.env の設定を確認

WEB_PORT=50012
DB_PORT=50013
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=testdb
MYSQL_USER=test
MYSQL_PASSWORD=testpassword

Dockerのデータベースに接続する必要があるので
Laravelの.envのデータベース接続の箇所を修正

Laravelの .env 場所

/laravel_app/.env

Dockerからの接続になるので、/docker-compose.yml を確認し
「DB_HOST」は「db」とし「DB_PORT」は「3306」であることに注意してください。

/laravel_app/.env 修正内容

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=testdb
DB_USERNAME=root
DB_PASSWORD=rootpassword

まだエラーが続きます。しぶといですね。

No application encryption key has been specified.

No application encryption key has been specified.

下記のコマンドを実行

キー作成

php artisan key:generate

キャッシュクリア

php artisan config:clear

これで、ようやくトップページが表示されました。
git cloneして、すぐに使えると思っていましたが、何点か注意が必要な状況でした。

私が作ったリポジトリに限らず、Laravelの .env はGit管理されない設定になっている為
他のLaravelのリポジトリを git clone して使えなかった場合には
上記の手順を参考にしていただければ幸いです。

あとがき

いくつになっても、新しい事を知ることは重要なのでめげずに進んでいきます。

健康診断もあり、30半ばになるとより一層健康が気になるところです。
では、そろそろ自分探し(再検査)に行ってまいります。

以上、西山でした。

git revert で本番反映をすぐ打消

こんにちは、エンジニアの西山です。

またクリエイターズブログの記事を書かせていただきます。

基本のGitの操作 commit, pull, push 等に慣れ作業を進めている時
本番サイトに反映した修正内容を、すぐ取り消して欲しいという要望も時にはあると思います。

修正ファイルや箇所が多く、急いで直している最中に限って
以下の事がよく起こります。

  • Slackでダイレクトチャットが飛んでくる
  • 隣の席の上司に声をかけられる
  • 先輩が息抜きにちょっかい出しにやってくる
  • 内線で呼び出される
  • 作業依頼をしていた方から質問を受ける
  • 別案件の緊急対応依頼

エンジニアあるあるですね。
どこまで直していたかを確認する為、時間を使い焦っていく。

そんな時に救ってくれるのが git revert です。

revert は リバートと読みます。
修正した内容を打ち消すコミットを行い、修正前の状態に戻してくれます。

早速、例を元に使っていきましょう。

■1. マージしていないコミットを打ち消し

テキストファイルを作成し
下記の内容を記載しコミットします。

コミットメッセージ 「太郎の最初のメッセージ」

僕は太郎です。花子さんが好きです。

文を追記し、コミットします。

コミットメッセージ 「花子さんと付き合えた」

僕は太郎です。花子さんが好きです。
花子さんと付き合うことになりました。

2行で付き合えるなら誰も苦労しませんね。
revert します。

まずは コミットの履歴を見ます。

Fumi-Mac:love fumi$ git log --graph
* commit 7a17b856e2af85b3d4b057614fdab832833748f1 (HEAD -> master)
| Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| Date:   Thu Jan 24 02:25:52 2019 +0900
|
|     花子さんと付き合えた
|
* commit 4723d015c345e0dd0016bd91df69aced7db0f6f9
| Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| Date:   Thu Jan 24 02:24:26 2019 +0900
|
|     太郎の最初のメッセージ
| 

「花子さんと付き合えた」というコミットのハッシュ値は
「7a17b856e2af85b3d4b057614fdab832833748f1」です。
打ち消したい内容であるこのハッシュ値を指定し、下記のコマンドを叩きます。

git revert 7a17b856e2af85b3d4b057614fdab832833748f1

ファイルを確認してください。「花子さんと付き合うことになりました。」という文が消えて
下記の状態になりました。

僕は太郎です。花子さんが好きです。

太郎は再び1人になりました。

■2. マージしたコミットを打ち消し

より実践的な例を見てみましょう。

実際の作業では修正用のブランチを作成し、修正内容をコミットします。
そして、本番反映時にブランチ「master」にマージするのがよく行われる流れかと思います。

ブランチ「master」から、ブランチ「hanako」を作成し
ブランチ「master」と、ブランチ「hanako」にそれぞれコミットを追加します。
最後に、ブランチ「hanako」を、ブランチ「master」にマージしました。

めでたく結ばれました。

全体のログ

Fumi-Mac:love fumi$ git log --graph
*   commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a (HEAD -> master)
|\  Merge: 88b202c a12f7c9
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:52:10 2019 +0900
| |
| |     Merge branch 'hanako'
| |
| * commit a12f7c9de1f18ac891e88d65c82453ae5acaee92 (hanako)
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:50:32 2019 +0900
| |
| |     花子コミット2
| |
| * commit 6a9bbbdf79c7d914ef214e614ca448aecedb899a
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:50:17 2019 +0900
| |
| |     花子コミット1
| |
* | commit 88b202c57a61f877a54fef5aeb4d31b850c25ebb
|/  Author: Fumitaka Nishiyama <xxxxx@gmail.com>
|   Date:   Thu Jan 24 02:48:15 2019 +0900
|
|       太郎コミット1

マージの箇所

*   commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a (HEAD -> master)
|\  Merge: 88b202c a12f7c9
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:52:10 2019 +0900
| |
| |     Merge branch 'hanako'

「88b202c」「a12f7c9」という2つの数字が記載されています。
これは親番号のハッシュ値です。
2つのブランチからマージされるので、それぞれの最後のコミットのハッシュ値の一部が記載されています。

ブランチ「master」の箇所

* | commit 88b202c57a61f877a54fef5aeb4d31b850c25ebb
|/  Author: Fumitaka Nishiyama <xxxxx@gmail.com>
|   Date:   Thu Jan 24 02:48:15 2019 +0900
|
|       太郎コミット1

ブランチ「hanako」の箇所

| * commit a12f7c9de1f18ac891e88d65c82453ae5acaee92 (hanako)
| | Author: Fumitaka Nishiyama <xxxxx@gmail.com>
| | Date:   Thu Jan 24 02:50:32 2019 +0900
| |
| |     花子コミット2

今回はブランチ「hanako」のマージを打ち消し
ブランチ「master」で「太郎コミット1」が反映されている状態にします。

現在のファイル内容

花子コミット1の内容です
花子コミット2の内容です
太郎です。
太郎コミット1の内容です

エラーになるリバート方法

git revert <マージコミット>

Fumi-Mac:love fumi$ git revert 46303cedb6e5ab634ee1f6b7f0ae28863d84868a
error: commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a is a merge but no -m option was given.
fatal: revert failed

ただマージコミットのハッシュ値を指定するだけでは
-m のオプションがないとエラーになります。

-m オプションが必要な理由

まず、「太朗コミット1」から「マージコミット」になった時に、どのような差がでているか確認します。

git diff <太郎コミット1> <マージコミット>

git diff 88b202c57a61f877a54fef5aeb4d31b850c25ebb 46303cedb6e5ab634ee1f6b7f0ae28863d84868a 

下記のように表示され、マージによりブランチ「hanako」の「花子コミット1」と「花子コミット2」により
文が2つ追加されているのが分かります。

+花子コミット1の内容です
+花子コミット2の内容です
太郎です。
太郎コミット1の内容です

実際にリバートをして説明いたします。
マージの箇所を確認します。

*   commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a (HEAD -> master)
|\  Merge: 88b202c a12f7c9
「補足」
88b202c の時は 1  ※ブランチ「master」のハッシュ値の一部 「太朗コミット1」
a12f7c9 の時は 2  ※ブランチ「hanako」のハッシュ値の一部 「花子コミット2」

git revert にオプション「-m」をつけ、ブランチ「master」の「太朗コミット1」の方を選ぶよう「1」を設定します。 マージコミットのハッシュ値「46303cedb6e5ab634ee1f6b7f0ae28863d84868a」を設定します。

リバートするコマンド

git revert -m 1 46303cedb6e5ab634ee1f6b7f0ae28863d84868a

実際にリバートした後のログを確認すると下記のようになります。

commit 9d9d9ece3d237065b87c81b963057a0ec069eb8d (HEAD -> master)
Author: Fumitaka Nishiyama <xxxxx@gmail.com>
Date:   Wed Feb 13 23:53:27 2019 +0900
Revert "Merge branch 'hanako'"
This reverts commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a, reversing
changes made to 88b202c57a61f877a54fef5aeb4d31b850c25ebb.

マージコミットとリバートコミットの差分を確認し
リバートでどのように変更されたか確認してみましょう。

git diff <マージコミット> <リバートコミット>

git diff 46303cedb6e5ab634ee1f6b7f0ae28863d84868a 9d9d9ece3d237065b87c81b963057a0ec069eb8d

リバートコミットにより、文が削除されているのが分かります。
マージにより追加された文が削除されています。

-花子コミット1の内容です
-花子コミット2の内容です
太郎です。
太郎コミット1の内容です

これにより、リバートとは
「マージコミット」と「戻すべきコミット」の差分を取得して、それとは逆のコミットを行うことが分かります。

その為、
「マージコミット」と「戻すべきコミット」との差分を取得するために
-m のオプションで、どのコミットが「戻すべきコミット」かを指定する必要があるのですね。

【マージをリバートするコマンド】

git revert -m <1や2等、戻すべきコミットを指定する数値> <マージコミット>

「参考」

例)git revert -m 1 46303cedb6e5ab634ee1f6b7f0ae28863d84868a
「マージの箇所」
*   commit 46303cedb6e5ab634ee1f6b7f0ae28863d84868a (HEAD -> master)
|\  Merge: 88b202c a12f7c9

これにより、ブランチ「hanako」のコミットが反映されていない状態になりました。
実際の業務で、ブランチ「master」にマージした修正ブランチの内容を打ち消した事と同様です。

あとがき

これで、基本のrevertの使い方を説明することができました。

git revert する時は緊急な時が多いので
コマンド1つで打ち消すことができて、感動しました!

私もこの記事を書くことによって、麻雀で負けた分を打ち消すことができました。
半荘が1回とは限らないのです。

以上、西山でした。

© SEEDS Co.,Ltd.