B-Teck!

お仕事からゲームまで幅広く

【MySQL/Docker】docker-composeでMySQL5.7のイメージを作成して接続する備忘録

参考にした記事

本記事はこれらの記事を参考に自分でDBを構築してみた作業メモとなります。
不明点があれば、下記の記事をご覧いただくことで解決するかもしれません。

環境

macOS Mojave 10.14.6  
Docker version 19.03.5, build 633a0ea  
docker-compose version 1.25.4, build 8d51620a  

最終的なプロジェクトのディレクトリ構成例(MySQLの場合)

今回は下記のようなプロジェクトを作成することを目標とします

sample-project/
             ├ docker/
             |       └ mysql/
             |              ├ conf.d/
             |              |       └ my.cnf
             |              ├ initdb.d/
             |              |       ├ data.csv
             |              |       ├ import.sh
             |              |       └ ddl.sql
             |              └ Dockerfile
             └ docker-compose.yml            

インストール

  • docker for macをインストール
    docker, docker-compose, docker-machineなどが同時にインストールされる
$ brew cask install docker

Dockerfileを作成する

Dockerfileにimageの内容を記述することでそのとおりのimageが作成される
MySQL 5.7のimageを作成するには下記のように記載する

FROM mysql:5.7
RUN touch /var/log/mysql/mysqld.log # 指定の場所にログを記録するファイルを作る

docker-compose.ymlを作成する

プロジェクト内に含んでいるServiceのportやvolumeなどの設定を行うことができる。

version: '3.3'
services:
  db:
    build: ./docker/mysql
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: sampledb
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: mysql
    ports:
      - "3314:3306"
    volumes:
      - ./docker/mysql/initdb.d:/docker-entrypoint-initdb.d
      - ./docker/mysql/conf.d:/etc/mysql/conf.d
      - ./log/mysql:/var/log/mysql

my.cnf(MySQLの設定ファイル)を作成する

[mysqld]
character-set-server=utf8mb4                # mysqlサーバー側が使用する文字コード
explicit-defaults-for-timestamp=1          # テーブルにTimeStamp型のカラムをもつ場合、推奨
general-log=1                              # 実行したクエリの全ての履歴を記録
general-log-file=/var/log/mysql/mysqld.log  # ログの出力先

[client]
default-character-set=utf8mb4               # mysqlのクライアント側が使用する文字コード

initdb.d配下配置したスクリプトでDBの初期化を行う

https://hub.docker.com/_/mysql/

Initializing a fresh instance When a container is started for the first time, a new database with the specified name will be created and initialized with the provided configuration variables. Furthermore, it will execute files with extensions .sh, .sql and .sql.gz that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. You can easily populate your mysql services by mounting a SQL dump into that directory and provide custom images with contributed data.

公式イメージは /docker-entrypoint-initdb.dに.sqlや.shを置いておけば初回起動時に実行 してくれる。
今回はdocker-compose.ymlのvolumeに ./docker/mysql/initdb.d:/docker-entrypoint-initdb.d を記載しているので、 /docker/mysql/initdb.d にリソースを配置する。

初期化処理でテーブル作成

  • 初期化用のDDLを配置
mysql/initdb.d/
            └ ddl.sql
  • ddl.sql
CREATE TABLE users (
    name VARCHAR(32) NOT NULL,
    email VARCHAR(32) NOT NULL
);

初期化処理でテストデータimport

  • 読み込み対象のcsv等と、それをimportする.shを配置
mysql/initdb.d/
            ├ data.csv
            └ import.sh
  • data.csv
exam taro,xxxx@mail.co.jp
  • import.sh
mysql -uroot -pmysql --local-infile sampledb -e "LOAD DATA LOCAL INFILE '/docker-entrypoint-initdb.d/data.csv' INTO TABLE users FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'"

プロジェクトのルートでdocker-composeコマンドを実行

今回の場合は sample-project/ 配下で実行します。

$ docker-compose up # コンテナを作成しスタートする
$ docker-compose ps # コンテナの状態を確認

各種コマンドメモ

  • up
    docker-compose.ymlで定義したサービスを開始または再起動する
  • run
    service名を指定して特定のサービスのコンテナと依存するコンテナを起動する
  • start
    既に作成済みのコンテナを再起動する
  • stop
    サービスを停止させる
  • down
    コンテナの停止、削除、さらにネットワーク、記憶領域を全て削除
  • ps
    存在するコンテナのリストを表示する

起動したMySQLに接続

コンテナ内からDBにアクセスできることを確認

$ docker exec -it sample-project_db_1 bash # sample-project_db_1コンテナでコマンドを実行
# mysql -u user -ppassword sampledb # 作成したmysqlにログイン
mysql> show tables; # テーブルが作られているか確認する
mysql> select * from users; # 仕込んだデータが入っているか確認する

ホスト名 ポートを指定してログイン

  • docker-compose ps でIP、portを確認
$ docker-compose ps
       Name                   Command            State            Ports         
--------------------------------------------------------------------------------
sample-project_db_1   docker-entrypoint.sh       Up      0.0.0.0:3314->3306/tcp,
                      mysqld                             33060/tcp              
  • 確認したIP, portをそれぞれhost、portに指定してログイン
$ mysql --host 0.0.0.0 --port 3314 -u user -ppassword

IntelliJやSQL Clientから接続する

GUI環境から接続する際には、ターミナル上で確認したhost名ではなく 127.0.0.1 を指定して接続する必要があるよう f:id:beatdjam:20200305114734p:plain

【本/DDD】 わかる! ドメイン駆動設計~もちこちゃんの大冒険~読書メモ

booth.pm

こちらの本を読みました。
ストーリー仕立てでドメイン駆動設計の戦略的な部分を平易に説明してくれる良本で、DDDの用語にとっつきづらさを感じていた自分にはちょうどよい内容でした。
戦術的な部分については一切書かれていないので注意。
次は「ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本」を読んで、戦術的な部分を抑えてみようかなと思ってます。

ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本

ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本

  • 作者:成瀬 允宣
  • 発売日: 2020/02/13
  • メディア: 単行本(ソフトカバー)

以下読書メモです

DDDってなに?

DDDとは

  • DDD = Domain Driven Design(ドメイン駆動設計)のこと
  • ドメイン駆動設計はソフトウェア開発手法であり、ソフトウェアモデルを設計する指針となる手法・理論・概念

DDDでは何をする?

  • 開発者とドメインエキスパートが協力してドメインを反映したモデル(ドメインモデル)を作り上げる
    • ドメインとはソフトウェアを適用する対象領域 ソフトウェアを通して表現したいなんらかの業務など
    • ドメインエキスパートとはドメインに対して知識を持っている人 業務の流れ/業務知識/既存設計/営業視点/実際の業務/運用の歴史など

ドメインを反映したモデル

  • ドメインを反映したモデルとは、ドメインを構成する物・概念・振る舞い・関係性を表現したもの 業務を構成するタスクがどのような関係性を持ち、どのような役割・振る舞いを期待されて存在しているか
  • DDDを効果的に行い、現実世界を適切に表したモデルを作るにはプロジェクトが下記のように進んでいると望ましい
    • 開発がイテレーティブである
    • 開発者とドメインエキスパートが密接に関わっている

DDDをすべき理由

  • ドメインエキスパートと開発者が相互に連携しモデルを作り上げることで、全員が業務・ソフトウェアを理解した状態を作り出せる

DDDの要素

  • DDDを構成する要素として、戦略的設計と戦術的設計がある
    • 戦略的設計
      • ユビキタス言語などの考え方や概念についてのもの
    • 戦術的設計
      • エンティティ・値オブジェクトなどの技術的手法
  • 戦術的設計だけを適用してもそれなりにメリットは得られるが、戦略的設計を行った上で戦術的設計を適用することがDDDの本旨

ユビキタス言語ってなに?

ユビキタス言語とは/ユビキタス言語を見つけるには

  • ドメインエキスパート・開発者間で共通となる、ドメインやその要素・振る舞いや関連性などを一意に表すための言葉
  • 関連する人間が同じものを同じ言葉で表すことが大事
    • そうでないものは徐々に排除し、置き換えていく

変化し続けるユビキタス言語

  • ユビキタス言語はソフトウェアの成長とともに常に変化しうるものであり、用語集的なものを用いると陳腐化しやすい
    • ので、ソフトウェアのコメントなどにできると良い

ユビキタス言語の適用範囲

  • 同じものを同じ言葉で話すことで認識の齟齬が減り、手戻りや修正、そもそもの認識の違いなどと言ったリスクが回避しやすくなる
  • プロジェクトの中での会話・ドキュメント・ソースコードなど、あらゆる範囲で同じ言葉を用いる

ユビキタス言語とドメインモデル

  • ドメインモデルはユビキタス言語で表されなければならない
  • つまり、ドメインモデル及びその実装についてユビキタス言語で定義できる状態になっていなければならない

ユビキタス言語の確立

  • 既に存在していたりするフレーズなどを収集する
    • 現在のドキュメントに存在するフレーズ 同じ存在を表しているもの/現象だけがあるもの/概念だけがあるもの
    • ドメインエキスパートが用いる言葉・単語
    • それらの振る舞いを表す言葉
  • 収集した言葉をチーム内で議論し、1つの言葉に収束させていく

ドメインモデル

ドメインモデルとは

  • ドメインを反映した概念的なモデル
  • チーム内での名前・関係性・振る舞いの概念を規定する
  • コードで表現されたドメインモデルが成果物であり、設計である状態を維持することがドメイン駆動設計

ドメインモデル貧血症

  • ドメインモデルが値を保持するだけのオブジェクトとなっていたり、ドメインモデルに振る舞いが規定されていない状態
  • ユビキタス言語に基づいてドメインの振る舞い・意図を実装したものこそがドメインオブジェクト

境界づけられたコンテキストって?

ドメインとは

  • 何らかの業務を表す領域のようなもの
  • 殆どのソフトウェアのドメインは複数のサブドメインの集合体である
    • サブドメインの種類
      • そのドメインを表すのに必要不可欠なコアドメイン
      • 業務にロックインしている、独自の機能、領域を表す支援サブドメイン
      • 十分に汎化され、なくても成り立つ、代替可能である汎用サブドメイン

境界づけられたコンテキストとは

  • ユビキタス言語やドメインの概念は、特定のコンテキストの中でのみ通用する概念である
  • サブドメイン単位であることもあれば、サブドメイン内で担当チームごとにコンテキストの境界が存在することもある
  • 解決したい問題に対して適切なサイズの境界付けを行うことで、チーム内が一つの概念を扱う形に統率できる

コンテキストマップ

コンテキストマップとは

  • 複数の境界付けられたコンテキストとその関係性を描いたもの
  • 境界付けられたコンテキスト自体の名前をユビキタス言語から取る

コンテキストマップの役割

  • ありのままの現状を表現する
  • それぞれのコンテキストの関係性、振る舞いについて、チーム内に共有と理解をもたらすもの

コンテキストマップを活用する

境界づけられたコンテキストの関係性のパターン

  • 共有カーネル
    • 2つのチーム間でコンテキストをやり取りをするための、ドメインモデルのサブセット
    • 自分たちのコンテキストと共有カーネルだけを意識すれば良くなる
  • 顧客/供給者の開発チーム
    • 2つのチームで開発しているシステムに相互の関係があり、片方が完全に依存している場合に適用できるパターン
      • 上流を供給者、下流を顧客と見立てて顧客と供給者という関係で定義する
      • 上流が下流の要望に答えるメリットがない場合はこのパターンの適用が難しい
    • 下流が要件を洗い出し、上流へ伝える
    • 上流は下流に対して要件を満たす適切なインターフェースを提供する
  • 順応者
    • 2つのチームで開発しているシステムに相互の関係があり、顧客と供給者の関係を築けない場合のパターン
    • 下流のチームが順応者として上流チームの提供するドメインモデルに従い開発するパターン
    • 上流のコンテキストに合わせた開発を行うため下流の負荷は高くなるが、開発を進めることは出来る
    • 順応者として振る舞えるほどコンテキストが単純でない場合、後述の腐敗防止層のパターンを用いることも出来る
  • 腐敗防止層
    • 境界づけられたコンテキスト間の変換にかかるコストが高い場合に、変換用のレイヤを用意するパターン
    • レイヤを持つことで独自のユビキタス言語、ドメインモデルを保つ
  • 別々の道
    • 要件を整理した結果コンテキスト間の関係が薄かった場合に、それらの関係を切り離して独立したドメインモデルとすること
  • 公開ホストサービス
    • 多くのコンテキストと関連する場合、個別に変換するレイヤを設けず、プロトコルとインターフェースを定義・公開するパターン
    • 1対他の共有カーネルのようなもの?
  • 公表された言語
    • 公開ホストサービスが提供するプロトコルとして利用する言語
    • 独自にプロトコルを生み出すのではなく、一般的に広く利用されているxmlやjsonなどを介すことで問題を簡単にする
  • 巨大な泥団子(巨大なコンテキスト)
    • 既存のシステムがドメインで整理されておらず、分割も難しい場合に一つのコンテキストとして隔離してしまうこと
    • 巨大なコンテキストの整理を一旦諦めて、腐敗防止層などを用意して腐敗が溶け込まないようにする

【雑記】前に進むしかないという話

※極個人的な感情の辛さを整理するために書いたものです。

ここ数日、数年ぶりに仕事で何も出来ていないなぁ、役に立てていないなぁという無力感を味わう毎日が続いている。

未知の既存プロダクトの再構築、かつ得手としていないDB部分の構築、1Bに共有され1Eからjoin、3Eまでに動くAPIを用意する業務。
要件の吸い上げ、理解、そして構成、何もかもわからないまま手探りで進んでいるし、何より難しいのが基本的に自分一人の案件で進める案件であることだ。
多忙なドメインエキスパートをうまく捕まえられれば質問や意見をもらうことなどが出来ないわけではないが、それをするには自分がまず理解して言語化しないといけない。
2月に入ってからは、半べそかきながら既存仕様を理解し、あるべき姿を脳内に作り上げ、それを元に意見を交わし、前に進む、の繰り返し。
本当に前に進んでいるのか、自分は何をしているのか、そんな事を自問する毎日で、精神が参らないはずはないなと思った。
この年齢になってその経験が出来ることはありがたいことでもあるけれど、つらいことでもあって、この業務に自分が携わる意味とは…とか、どうせ間に合わないでしょ…とか、そんな事を考えてばかりいた。

正直今でもその気持ちは拭えていないし、諦念半分といったところではあるのだけど、あまりの辛さから急に風呂場で瞑想をしたり、月曜日に絶望したりしていたら、急にタイトルのような心境になったので、忘れないようにこの文章を書いてる。

人生、諦観したところで動きを止めてくれるわけでもなく、流され続けるしかないので、結局流されるか自分の意志で進むしかないのだ。
どうせ進むなら自分の意志で進めたほうがいい。それで駄目だったとして、それはその時考えればいい話で、今考えることではないなってなった。

今の仕事は楽しいし、なるべくやっていきたいなと思っているけど、万が一このプロジェクトが失敗して評価・評判がボロクソになって居場所がなくなろうが、働ける企業が現職一つであるわけでもない。
それだったら成功したときのプラスを最大化出来るようにしたほうが、結果的に得だよねという結論にまで至ることで、どうにかメンタルを持ち直してきた。

万が一ここまで読んだ人がもしいたら私が4月を笑って迎えられるよう祈っていてください。


石風呂 / 壊れぬハートが欲しいのだ【OFFICIAL MUSIC VIDEO】