メインコンテンツにスキップ

5件の投稿件の投稿が「docker」タグ付き

すべてのタグを見る

Spring Boot 3.1におけるDocker Composeサポートの探求

· 4分の読み時間
Haril Song
Owner, Software Engineer at 42dot

Spring Boot 3.1で導入されたDocker Composeサポートについて簡単に見ていきましょう。

情報

不正確な点があればフィードバックをお願いします!

概要

Springフレームワークで開発する際、DB環境をローカルマシンに直接インストールするよりも、Dockerを使用してセットアップする方が一般的なようです。通常のワークフローは以下の通りです:

  1. bootRunの前にdocker runを使用してDBを起動状態にする
  2. bootRunを使用して開発および検証作業を行う
  3. bootRunを停止し、docker stopを使用してコンテナDBを停止する

開発作業の前後にDockerを実行および停止するプロセスは非常に面倒でした。しかし、Spring Boot 3.1からは、docker-compose.yamlファイルを使用してSpringとDockerコンテナのライフサイクルを同期させることができます。

内容

まず、依存関係を追加します:

dependencies {
// ...
developmentOnly 'org.springframework.boot:spring-boot-docker-compose'
// ...
}

次に、以下のようにcomposeファイルを作成します:

services:
elasticsearch:
image: 'docker.elastic.co/elasticsearch/elasticsearch:7.17.10'
environment:
- 'ELASTIC_PASSWORD=secret'
- 'discovery.type=single-node'
- 'xpack.security.enabled=false'
ports:
- '9200' # ランダムポートマッピング
- '9300'

image

bootRunの際に、composeファイルが自動的に認識され、docker compose up操作が最初に実行されます。

ただし、コンテナポートをランダムなホストポートにマッピングしている場合、docker compose downがトリガーされるたびにapplication.ymlを更新する必要があるかもしれません。幸いなことに、Spring Boot 3.1からは、composeファイルを書くだけでSpring Bootが残りの作業を引き受けてくれます。非常に便利です!

composeファイルのパスを変更する必要がある場合は、fileプロパティを変更するだけです:

spring:
docker:
compose:
file: infrastructure/compose.yaml

ライフサイクル管理に関連するプロパティもあり、コンテナのライフサイクルを適切に調整できます。Bootをシャットダウンするたびにコンテナを停止したくない場合は、start_onlyオプションを使用できます:

spring:
docker:
compose:
lifecycle-management: start_and_stop # none, start_only

他にもさまざまなオプションがあるので、探求してみると良いでしょう。

image

結論

どれだけテストコードを書いても、実際のDBとの相互作用を検証することは開発プロセスにおいて不可欠でした。その環境をセットアップすることは面倒な作業に感じられました。コンテナ技術により設定は非常に簡単になりましたが、Spring Bootを起動する前後にdockerコマンドを実行することを忘れないようにするのは手間でした。

しかし、Spring Boot 3.1からは、コンテナの起動や停止を忘れることがなくなり、メモリ消費を防ぐことができます。これにより、開発者は開発にもっと集中できるようになります。DockerとSpringのシームレスな統合は非常に魅力的で便利です。ぜひ試してみてください!

参考

有効なDocker環境が見つかりませんでした

· 2分の読み時間
Haril Song
Owner, Software Engineer at 42dot

概要

Macをアップデートした後、Dockerが正常に動作しなくなり、再インストールする必要がありました。しかし、テストを実行するとコンテナが正常に動作しないエラーに遭遇しました。

調べてみると、/var/run/docker.sockが正しく設定されていないことが原因でした。ここでは、この問題を解決する方法を共有します。

説明

この問題はDocker Desktopバージョン4.13.0で発生します。

デフォルトでは、Dockerはホスト上に/var/run/docker.sockシンボリックリンクを作成せず、代わりにdocker-desktop CLIコンテキストを使用します。 (参照: https://docs.docker.com/desktop/release-notes/)

現在のDockerコンテキストはdocker context lsコマンドで確認できます。以下のように表示されます:

NAME                TYPE                DESCRIPTION                               DOCKER ENDPOINT                                KUBERNETES ENDPOINT                                 ORCHESTRATOR
default moby Current DOCKER_HOST based configuration unix:///var/run/docker.sock https://kubernetes.docker.internal:6443 (default) swarm
desktop-linux * moby unix:///Users/<USER>/.docker/run/docker.sock

問題を解決するには、デフォルトのコンテキストを設定するか、unix:///Users/<USER>/.docker/run/docker.sockに接続します。

解決方法

以下のコマンドを実行してデフォルトのコンテキストに切り替え、Dockerが正常に動作するか確認してください:

docker context use default

問題が解決しない場合は、以下のコマンドでシンボリックリンクを手動で作成して解決できます:

sudo ln -svf /Users/<USER>/.docker/run/docker.sock /var/run/docker.sock

参考

Dockerネットワーク

· 8分の読み時間
Haril Song
Owner, Software Engineer at 42dot

概要

Dockerコンテナは隔離された環境で実行されるため、デフォルトでは互いに通信できません。しかし、複数のコンテナを1つのDockerネットワークに接続することで、相互に通信が可能になります。この記事では、異なるコンテナ間の通信を実現するためのネットワーク設定方法について探ります。

ネットワークの種類

Dockerネットワークは、目的に応じてbridgehostoverlayなどのさまざまなネットワークドライバーをサポートしています。

  • bridge: 単一ホスト内の複数のコンテナ間で通信を可能にします。
  • host: コンテナをホストコンピュータと同じネットワークで実行するために使用されます。
  • overlay: 複数のホスト上で実行されるコンテナ間のネットワーキングに使用されます。

ネットワークの作成

docker network createコマンドを使用して、新しいDockerネットワークを作成しましょう。

docker network create my-net

新しく追加されたネットワークは、docker network lsコマンドを使用して確認できます。-dオプションを指定しなかったため、デフォルトのbridgeネットワークとして作成されたことが確認できます。

ネットワークの詳細

docker network inspectコマンドを使用して、新しく追加されたネットワークの詳細を確認しましょう。

docker network inspect my-net
[
{
"Name": "my-net",
"Id": "05f28107caa4fc699ea71c07a0cb7a17f6be8ee65f6001ed549da137e555b648",
"Created": "2022-08-02T09:05:20.250288712Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]

Containersセクションを確認すると、このネットワークに接続されているコンテナがないことがわかります。

コンテナをネットワークに接続する

まず、oneという名前のコンテナを実行しましょう。

docker run -it -d --name one busybox
# af588368c67b8a273cf63a330ee5191838f261de1f3e455de39352e0e95deac4

コンテナを実行する際に--networkオプションを指定しない場合、デフォルトでbridgeネットワークに接続されます。

情報

busyboxは、テスト目的に最適な軽量のコマンドラインライブラリであり、Dockerが公式に提供しています。

docker network inspect bridge
#...
"Containers": {
"af588368c67b8a273cf63a330ee5191838f261de1f3e455de39352e0e95deac4": {
"Name": "one",
"EndpointID": "44a4a022cc0f5fb30e53f0499306db836fe64da15631f2abf68ebc74754d9750",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
#...
]

次に、docker network connectコマンドを使用して、oneコンテナをmy-netネットワークに接続しましょう。

docker network connect my-net one

my-netネットワークの詳細を再確認すると、oneコンテナがContainersセクションに追加され、IPアドレス172.18.0.2が割り当てられていることがわかります。

docker network inspect my-net
[
{
"Name": "my-net",
"Id": "05f28107caa4fc699ea71c07a0cb7a17f6be8ee65f6001ed549da137e555b648",
"Created": "2022-08-02T09:05:20.250288712Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"af588368c67b8a273cf63a330ee5191838f261de1f3e455de39352e0e95deac4": {
"Name": "one",
"EndpointID": "ac85884c9058767b037b88102fe6c35fb65ebf91135fbce8df24a173b0defcaa",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]

コンテナをネットワークから切断する

コンテナは同時に複数のネットワークに接続できます。oneコンテナは最初にbridgeネットワークに接続されていたため、現在はmy-netbridgeの両方のネットワークに接続されています。

docker network disconnectコマンドを使用して、oneコンテナをbridgeネットワークから切断しましょう。

docker network disconnect bridge one

2つ目のコンテナを接続する

次に、twoという名前のコンテナをmy-netネットワークに接続しましょう。

今回は、コンテナを実行する際に--networkオプションを使用して接続するネットワークを指定します。

docker run -it -d --name two --network my-net busybox
# b1509c6fcdf8b2f0860902f204115017c3e2cc074810b330921c96e88ffb408e

my-netネットワークの詳細を確認すると、twoコンテナがIPアドレス172.18.0.3を割り当てられて接続されていることがわかります。

docker network inspect my-net
[
{
"Name": "my-net",
"Id": "05f28107caa4fc699ea71c07a0cb7a17f6be8ee65f6001ed549da137e555b648",
"Created": "2022-08-02T09:05:20.250288712Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"af588368c67b8a273cf63a330ee5191838f261de1f3e455de39352e0e95deac4": {
"Name": "one",
"EndpointID": "ac85884c9058767b037b88102fe6c35fb65ebf91135fbce8df24a173b0defcaa",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
},
"b1509c6fcdf8b2f0860902f204115017c3e2cc074810b330921c96e88ffb408e": {
"Name": "two",
"EndpointID": "f6e40a7e06300dfad1f7f176af9e3ede26ef9394cb542647abcd4502d60c4ff9",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]

コンテナ間のネットワーキング

2つのコンテナがネットワーク上で通信できるかどうかをテストしましょう。

まず、oneコンテナからtwoコンテナにpingコマンドを使用してpingを送ります。コンテナ名をホスト名として使用できます。

docker exec one ping two
# PING two (172.18.0.3): 56 data bytes
# 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.114 ms
# 64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.915 ms

次に、twoコンテナからoneコンテナにpingを送ります。

docker exec two ping one
# PING one (172.18.0.2): 56 data bytes
# 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.108 ms
# 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.734 ms
# 64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.270 ms
# 64 bytes from 172.18.0.2: seq=3 ttl=64 time=0.353 ms
# 64 bytes from 172.18.0.2: seq=4 ttl=64 time=0.371 ms

両方のコンテナがスムーズに通信できることが確認できました。

ネットワークの削除

最後に、docker network rmコマンドを使用してmy-netネットワークを削除しましょう。

docker network rm my-net
# Error response from daemon: error while removing network: network my-net id 05f28107caa4fc699ea71c07a0cb7a17f6be8ee65f6001ed549da137e555b648 has active endpoints

削除しようとしているネットワークにアクティブなコンテナが存在する場合、ネットワークは削除されません。

その場合、ネットワークを削除する前に、そのネットワークに接続されているすべてのコンテナを停止する必要があります。

docker stop one two
# one
# two
docker network rm my-net
# my-net

ネットワークのクリーンアップ

ホスト上で複数のコンテナを実行していると、コンテナが接続されていないネットワークが残ることがあります。そのような場合、docker network pruneコマンドを使用して、不要なネットワークを一度にすべて削除できます。

docker network prune
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N] y

結論

この記事では、さまざまなdocker networkコマンドについて探りました:

  • ls
  • create
  • connect
  • disconnect
  • inspect
  • rm
  • prune

ネットワークの理解は、Dockerコンテナを扱う際に重要です。データベースのコンテナ化やコンテナクラスタリングの実装など、複数のコンテナを効果的に管理するための重要なスキルです。

参考文献

Docker Volume

· 6分の読み時間
Haril Song
Owner, Software Engineer at 42dot

概要

Dockerコンテナはデフォルトで完全に隔離されています。つまり、コンテナ内のデータはホストマシンからアクセスできません。これは、コンテナのライフサイクルがその内部データに完全に依存していることを意味します。簡単に言えば、コンテナが削除されると、そのデータも失われます。

では、ログやデータベース情報などの重要なデータをコンテナのライフサイクルに依存せずに永続的に保存するにはどうすればよいでしょうか?

ここで ボリューム が登場します。

PostgreSQLのローカルインストール

簡単な例でPostgreSQLをインストールして使用しながら、ボリュームについて探ってみましょう。

ボリュームを使用しない場合

1. イメージをプルする

docker run -p 5432:5432 --name postgres -e POSTGRES_PASSWORD=1234 -d postgres

2. PostgreSQLに接続する

docker exec -it postgres psql -U postgres

3. ユーザーを作成する

create user testuser password '1234' superuser;

4. データベースを作成する

create database testdb owner testuser;

DBeaverDataGrip などのツールを使用してユーザーやデータベースを作成することもできます。

作業が終わったら、docker stop postgres でコンテナを停止できます。docker ps -a でコンテナリストを確認すると、コンテナが停止しているが削除されていないことがわかります。

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5c72a3d21021 postgres "docker-entrypoint.s…" 54 seconds ago Exited (0) 43 seconds ago postgres

この状態では、docker start postgres でコンテナを再起動でき、データはまだ存在しています。

これを確認してみましょう。

PostgreSQLで \list コマンドを使用すると、testdb データベースがまだ存在していることがわかります。

postgres=# \list
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+-----------------------
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
testdb | testuser | UTF8 | en_US.utf8 | en_US.utf8 |
(4 rows)

しかし、docker rm オプションを使用してコンテナを完全に削除した場合はどうなるでしょうか?

docker rm postgres を実行し、その後 docker run を再度実行すると、新しいコンテナが作成され、testdb とユーザーが消えていることがわかります。

$ docker rm postgres
postgres
$ docker run -p 5432:5432 --name postgres -e POSTGRES_PASSWORD=1234 -d postgres
67c5c39658f5a21a833fd2fab6058f509ddac110c72749092335eec5516177c2
$ docker exec -it postgres psql -U postgres
psql (14.4 (Debian 14.4-1.pgdg110+1))
Type "help" for help.

postgres=# \list
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+-----------------------
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
(3 rows)

postgres=#

ボリュームを使用する場合

まず、ボリュームを作成します。

$ docker volume create postgres
postgres

ls コマンドでボリュームの作成を確認できます。

$ docker volume ls
DRIVER VOLUME NAME
local postgres

次に、作成したボリュームをマウントしてPostgreSQLコンテナを実行します。

$ docker run -p 5432:5432 --name postgres -e POSTGRES_PASSWORD=1234 -v postgres:/var/lib/postgresql/data -d postgres
002c552fe092da485ee30235d809c835eeb08bd7c00e6f91a2f172618682c48e

その後の手順は、ボリュームを使用しない場合と同じです。これで、docker rm を使用してコンテナを完全に削除しても、データはボリュームに残り、失われることはありません。

前述のように、ログファイルやバックアップデータの長期保存には、ボリュームを使用してデータの永続性を確保することができます。

結論

Dockerボリュームとは何か、そしてそれをどのように使用するかをPostgreSQLの例を通じて探りました。ボリュームはDockerコンテナにおけるデータ管理の重要なメカニズムです。コンテナの性質に応じて適切にボリュームを使用することで、データを安全かつ簡単に管理でき、慣れれば開発の生産性を大幅に向上させることができます。詳細な情報については、公式ドキュメント を参照してください。

参考文献

なぜDockerなのか?

· 9分の読み時間
Haril Song
Owner, Software Engineer at 42dot
情報

この記事は社内情報共有のために書かれており、Java開発環境を基に説明しています。

Dockerとは?

情報

Linuxコンテナを作成・使用するためのコンテナ技術であり、この技術をサポートする最大の企業の名前でもあり、オープンソースプロジェクトの名前でもあります。

deploy-history 誰もが一度はDockerを検索したときに見たことがある画像

2013年に導入されたDockerは、インフラの世界をコンテナ中心のものに変革しました。多くのアプリケーションがコンテナを使用してデプロイされ、Dockerfileを作成してイメージをビルドし、コンテナをデプロイすることが一般的な開発プロセスとなりました。2019年のDockerConプレゼンテーションでは、1052億回ものコンテナイメージのプルが報告されました。

Dockerを使用することで、非常に軽量なモジュール型の仮想マシンのようにコンテナを扱うことができます。さらに、コンテナは柔軟にビルド、デプロイ、コピー、移動が可能で、クラウド向けのアプリケーション最適化をサポートします。

Dockerコンテナの利点

どこでも一貫した動作

コンテナランタイムがインストールされている限り、Dockerコンテナはどこでも同じ動作を保証します。例えば、チームメンバーAがWindows OSを使用し、チームメンバーBがMacOSを使用している場合でも、Dockerfileを通じてイメージを共有することで、OSに関係なく同じ結果を確認できます。デプロイの場合も同様です。コンテナが正常に動作することが確認されていれば、追加の設定なしでどこでも正常に動作します。

モジュール性

Dockerのコンテナ化アプローチは、アプリケーションの一部を分解、更新、または回復する能力に焦点を当てています。サービス指向アーキテクチャ(SOA)のように、複数のアプリケーション間でプロセスを共有するマイクロサービスベースのアプローチを採用できます。

レイヤリングとイメージバージョン管理

各Dockerイメージファイルは一連のレイヤーで構成されており、これらが一つのイメージに結合されます。

Dockerは新しいコンテナをビルドする際にこれらのレイヤーを再利用するため、ビルドプロセスが非常に速くなります。中間の変更はイメージ間で共有され、速度、スケーラビリティ、効率が向上します。

高速なデプロイ

Dockerベースのコンテナはデプロイ時間を数秒に短縮できます。OSを起動してコンテナを追加または移動する必要がないため、デプロイ時間が大幅に短縮されます。さらに、高速なデプロイ速度により、コンテナによって生成されたデータの作成と削除がコスト効率よく簡単に行え、ユーザーはそれが正しく行われたかどうかを心配する必要がありません。

要するに、Docker技術は効率性を強調し、より細かく制御可能なマイクロサービスベースのアプローチを提供します

ロールバック

Dockerを使用してデプロイする際、イメージはタグ付きで使用されます。例えば、バージョン1.2のイメージを使用してデプロイし、リポジトリにバージョン1.1のイメージがまだある場合、jarファイルを再準備することなくコマンドを実行するだけで済みます。

docker run --name app image:1.2
docker stop app

## バージョン1.1を実行
docker run --name app image:1.1

Docker使用前後の比較

Dockerコンテナを使用することで、従来の方法に比べてはるかに迅速かつ柔軟なデプロイが可能になります。

Dockerコンテナを使用しないデプロイ

  1. ローカルマシンでデプロイするjarファイルをパッケージ化。
  2. scpなどのファイル転送プロトコルを使用してjarファイルを本番サーバーに転送。
  3. ステータス管理のためにsystemctlを使用してサービスファイルを作成。
  4. systemctl start appでアプリケーションを実行。

複数のアプリが1つのサーバーで実行されている場合、停止したアプリを見つけるのは非常に複雑になります。複数のサーバーで複数のアプリを実行する場合も同様で、各サーバーでコマンドを実行する必要があり、非常に疲れるプロセスです。

Dockerコンテナを使用したデプロイ

  1. Dockerfileを使用してアプリケーションのイメージを作成。→ ビルド ⚒️
  2. DockerhubやGitlabレジストリなどのリポジトリにイメージをプッシュ。→ シッピング🚢
  3. 本番サーバーでdocker run imageを使用してアプリケーションを実行。

複雑なパス設定やファイル転送プロセスに時間を浪費する必要はありません。Dockerはどの環境でも動作し、どこでも実行され、リソースを効率的に使用します。

Dockerは単一のコンテナを効果的に管理するように設計されています。しかし、数百のコンテナやコンテナ化されたアプリを使用し始めると、管理とオーケストレーションが非常に困難になります。すべてのコンテナにネットワーキング、セキュリティ、テレメトリなどのサービスを提供するためには、一歩引いてそれらをグループ化する必要があります。ここでKubernetes1が登場します。

いつ使用すべきか?

開発者はほぼすべての状況でDockerを非常に有用と感じるでしょう。実際、Dockerは開発、デプロイ、運用において従来の方法よりも優れていることが多いため、Dockerコンテナは常に最優先で検討すべきです。

  1. ローカルマシンでPostgreSQLのような開発データベースが必要なとき。
  2. 新しい技術をテストまたは迅速に採用したいとき。
  3. ローカルマシンに直接インストールまたはアンインストールが難しいソフトウェアがあるとき(例:WindowsでJavaを再インストールするのは悪夢です)。
  4. フロントエンドチームなど、他のチームから最新のデプロイバージョンをローカルマシンで実行したいとき。
  5. 本番サーバーをNCPからAWSに切り替える必要があるとき。

シンプルなAPIサーバー:

docker run --name rest-server -p 80:8080 songkg7/rest-server
# curlを使用
curl http://localhost/ping

# httpieを使用
http localhost/ping

ポート80がコンテナのポート8080にマッピングされているため、コンテナとの通信がうまくいくことが確認できます。

よく使われるDocker Runオプション

--name : コンテナに名前を付ける

-p : コンテナのポートをホストに公開する

--rm : コンテナが終了したときに自動的に削除する

-i : インタラクティブモード、アタッチされていなくてもSTDINを開いたままにする

-t : 擬似TTYを割り当て、ターミナルに似た環境を作成する

-v : ボリュームをバインドマウントする

結論

Dockerコンテナを使用することで、従来のデプロイ方法で発生する問題を解決しながら、便利な操作が可能になります。次回は、アプリケーションのイメージを作成するDockerfileについて見ていきます。

参考文献


Footnotes

  1. Kubernetes