6件の投稿件の投稿が「docker」タグ付き
すべてのタグを見るSpring Boot 3.1におけるDocker Composeサポートの探求
Spring Boot 3.1で導入されたDocker Composeサポートについて簡単に見ていきましょう。
不正確な点があればフィードバックをお願いします!
概要
Springフレームワークで開発する際、DB環境をローカルマシンに直接インストールするよりも、Dockerを使用してセットアップする方が一般的なようです。通常のワークフローは以下の通りです:
bootRun
の前にdocker run
を使用してDBを起動状態にするbootRun
を使用して開発および検証作業を行う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'
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
他にもさまざまなオプションがあるので、探求してみると良いでしょう。
結論
どれだけテストコードを書いても、実際のDBとの相互作用を検証することは開発プロセスにおいて不可欠でした。その環境をセットアップすることは面倒な作業に感じられました。コンテナ技術により設定は非常に簡単になりましたが、Spring Bootを起動する前後にdocker
コマンドを実行することを忘れないようにするのは手間でした。
しかし、Spring Boot 3.1からは、コンテナの起動や停止を忘れることがなくなり、メモリ消費を防ぐことができます。これにより、開発者は開発にもっと集中できるようになります。DockerとSpringのシームレスな統合は非常に魅力的で便利です。ぜひ試してみてください!
参考
有効なDocker環境が見つかりませんでした
概要
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ネットワーク
概要
Dockerコンテナは隔離された環境で実行されるため、デフォルトでは互いに通信できません。しかし、複数のコンテナを1つのDockerネットワークに接続することで、相互に通信が可能になります。この記事では、異なるコンテナ間の通信を実現するためのネットワーク設定方法について探ります。
ネットワークの種類
Dockerネットワークは、目的に応じてbridge
、host
、overlay
などのさまざまなネットワークドライバーをサポートしています。
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-net
とbridge
の両方のネットワークに接続されています。
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
概要
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;
DBeaver
や DataGrip
などのツールを使用してユーザーやデータベースを作成することもできます。
作業が終わったら、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なのか?
この記事は社内情報共有のために書かれており、Java開発環境を基に説明しています。
Dockerとは?
Linuxコンテナを作成・使用するためのコンテナ技術であり、この技術をサポートする最大の企業の名前でもあり、オープンソースプロジェクトの名前でもあります。
誰もが一度は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コンテナを使用しないデプロイ
- ローカルマシンでデプロイする
jar
ファイルをパッケージ化。 scp
などのファイル転送プロトコルを使用してjar
ファイルを本番サーバーに転送。- ステータス管理のために
systemctl
を使用してサービスファイルを作成。 systemctl start app
でアプリケーションを実行。
複数のアプリが1つのサーバーで実行されている場合、停止したアプリを見つけるのは非常に複雑になります。複数のサーバーで複数のアプリを実行する場合も同様で、各サーバーでコマンドを実行する必要があり、非常に疲れるプロセスです。
Dockerコンテナを使用したデプロイ
Dockerfile
を使用してアプリケーションのイメージを作成。→ ビルド ⚒️- DockerhubやGitlabレジストリなどのリポジトリにイメージをプッシュ。→ シッピング🚢
- 本番サーバーで
docker run image
を使用してアプリケーションを実行。
複雑なパス設定やファイル転送プロセスに時間を浪費する必要はありません。Dockerはどの環境でも動作し、どこでも実行され、リソースを効率的に使用します。
Dockerは単一のコンテナを効果的に管理するように設計されています。しかし、数百のコンテナやコンテナ化されたアプリを使用し始めると、管理とオーケストレーションが非常に困難になります。すべてのコンテナにネットワーキング、セキュリティ、テレメトリなどのサービスを提供するためには、一歩引いてそれらをグループ化する必要があります。ここでKubernetes1が登場します。
いつ使用すべきか?
開発者はほぼすべての状況でDockerを非常に有用と感じるでしょう。実際、Dockerは開発、デプロイ、運用において従来の方法よりも優れていることが多いため、Dockerコンテナは常に最優先で検討すべきです。
- ローカルマシンでPostgreSQLのような開発データベースが必要なとき。
- 新しい技術をテストまたは迅速に採用したいとき。
- ローカルマシンに直接インストールまたはアンインストールが難しいソフトウェアがあるとき(例:WindowsでJavaを再インストールするのは悪夢です)。
- フロントエンドチームなど、他のチームから最新のデプロイバージョンをローカルマシンで実行したいとき。
- 本番サーバーを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にマッピングされているため、コンテナとの通信がうまくいくことが確認できます。
--name
: コンテナに名前を付ける
-p
: コンテナのポートをホストに公開する
--rm
: コンテナが終了したときに自動的に削除する
-i
: インタラクティブモード、アタッチされていなくてもSTDINを開いたままにする
-t
: 擬似TTYを割り当て、ターミナルに似た環境を作成する
-v
: ボリュームをバインドマウントする
結論
Dockerコンテナを使用することで、従来のデプロイ方法で発生する問題を解決しながら、便利な操作が可能になります。次回は、アプリケーションのイメージを作成するDockerfile
について見ていきます。