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

ZonedDateTimeを使用する際の注意点 - Object.equals vs Assertions.isEqualTo

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

概要

Javaには時間を表現するためのオブジェクトがいくつか存在します。この記事では、その中でも最も情報量が多いZonedDateTimeを使用した時間の比較方法について説明します。

異なるが同じ時間?

まず、簡単なテストコードを書いて、何か特異な点がないか確認してみましょう。

ZonedDateTime seoulZonedTime = ZonedDateTime.parse("2021-10-10T10:00:00+09:00[Asia/Seoul]");
ZonedDateTime utcTime = ZonedDateTime.parse("2021-10-10T01:00:00Z[UTC]");

assertThat(seoulZonedTime.equals(utcTime)).isFalse();
assertThat(seoulZonedTime).isEqualTo(utcTime);

このコードはテストに合格します。equalsfalseを返す一方で、isEqualToは合格します。なぜでしょうか?

実際には、上記のコードにおける2つのZonedDateTimeオブジェクトは同じ時間を表しています。しかし、ZonedDateTimeは内部的にLocalDateTimeZoneOffset、およびZoneIdを含んでいるため、equalsを使用して比較すると、絶対時間ではなくオブジェクトの値が同じかどうかをチェックします。

そのため、equalsfalseを返します。

image1 ZonedDateTime#equals

しかし、isEqualToは時間オブジェクトの操作に関して異なる動作をするようです。

実際、ZonedDateTimeを比較する際、isEqualToZonedDateTimeequalsを呼び出すのではなく、ChronoZonedDateTimeByInstantComparator#compareを呼び出します。

image2

image3 Comparator#compareが呼び出される。

内部実装を見ると、toEpochSecond()を使用して秒に変換することで比較が行われていることがわかります。つまり、equalsを通じてオブジェクトを比較するのではなく、compareを通じて絶対時間を比較しています。

これに基づいて、ZonedDateTimeの比較を以下のようにまとめることができます:

equals : オブジェクトを比較

isEqualTo : 絶対時間を比較

したがって、ZonedDateTimeを間接的に含むオブジェクトを比較する場合、equalsが呼び出されるため、ZonedDateTimeの絶対値に基づいて比較したい場合は、オブジェクト内でequalsメソッドをオーバーライドする必要があります。

public record Event(
String name,
ZonedDateTime eventDateTime
) {
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Event event = (Event) o;
return Objects.equals(name, event.name)
&& Objects.equals(eventDateTime.toEpochSecond(), event.eventDateTime.toEpochSecond());
}

@Override
public int hashCode() {
return Objects.hash(name, eventDateTime.toEpochSecond());
}
}
@Test
void equals() {
ZonedDateTime time1 = ZonedDateTime.parse("2021-10-10T10:00:00+09:00[Asia/Seoul]");
ZonedDateTime time2 = ZonedDateTime.parse("2021-10-10T01:00:00Z[UTC]");

Event event1 = new Event("event", time1);
Event event2 = new Event("event", time2);

assertThat(event1).isEqualTo(event2); // pass
}

結論

  • ZonedDateTime間でequalsが呼び出される際に絶対時間を比較したい場合は、toEpochSecond()などを使用して変換する必要があります。
  • テストコードや類似のシナリオでisEqualToを使用して直接ZonedDateTimeを比較する場合、equalsは呼び出されず、内部変換が行われるため、別途変換する必要はありません。
  • オブジェクト内にZonedDateTimeが含まれている場合、必要に応じてオブジェクトのequalsメソッドをオーバーライドする必要があります。

DockerでJenkinsを運用する

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

概要

この記事では、Dockerを使用してJenkinsをインストールおよび運用する方法について説明します。

目次

インストール

Docker

docker run --name jenkins-docker -d -p 8080:8080 -p 50000:50000 -v /home/jenkins:/var/jenkins_home -u root jenkins/jenkins:lts 

ホストマシン上にJenkinsデータを永続化するためにボリュームをマウントします。TeamCityとは異なり、Jenkinsはすべての設定をファイルで管理します。マウントを設定することで、認証情報やデータ管理が非常に便利になるため、必ず設定してください。一般的なターゲットパスは/home/jenkinsまたは/var/lib/jenkinsです。

この記事の目的のために、/home/jenkinsパスが作成されていると仮定します。

認証

マスターとノードの両方に対するセキュリティとアクセス制御を確保するために、'jenkins'という名前のユーザーを作成し、以下の手順に従います。

ユーザーアクセス権の設定

chown -R jenkins /var/lib/jenkins

SSHキーの管理

キーがない場合は、ssh-keygenを使用してプライベートキーとパブリックキーを生成します。

パスの入力を求められたら、/home/jenkins/.ssh/id_rsaと入力して、キーが/home/jenkins/.sshに作成されるようにします。

GitLab

GitLabの個人設定にはSSH設定タブがあります。そこにパブリックキーを追加します。

パイプラインでGitを選択すると、リポジトリパスの入力フィールドが表示されます。git@~で始まるSSHパスを入力すると赤いエラーが表示されます。これを解決するために、資格情報を作成します。SSH資格情報を選択して作成し、ID値には有用な値を入力することをお勧めします。

ノード設定

ノードはJenkinsの役割を効率的に分散する方法です。

ノードと通信するために、マスターでssh-keygenを使用してキーを生成します。既に使用しているキーがある場合は、それを再利用できます。

image

  • ID: この値はJenkinsが内部でSSHキーを識別するために使用され、Jenkinsfileで資格情報を使用しやすくするため、意味のある値を設定するのがベストです。設定しない場合はUUID値が生成されます。
  • Username: Linuxユーザー。通常、'jenkins'がユーザーとして使用されるため、'jenkins'と入力します。これを入力しないと、キーエラーが発生する可能性があるので注意してください

Dockerアクセス権限

dockerグループが存在しない場合は、作成します。通常、Dockerをインストールすると自動的に作成されます。

sudo groupadd docker

以下のコマンドを実行して、JenkinsユーザーにDockerを実行する権限を付与します。

sudo gpasswd -a jenkins docker
# Adding user jenkins to group docker
sudo chmod 666 /var/run/docker.sock

変更を適用するためにDockerデーモンを再起動します。

systemctl restart docker

これでdocker psコマンドを実行できるようになります。

再起動

Jenkinsのバージョンを更新したり、プラグインをインストール、削除、更新したりすると、Jenkinsが再起動します。しかし、Dockerで管理している場合、コンテナがダウンし、Jenkinsが起動できなくなります。再起動を有効にするには、コンテナに再起動ポリシーを設定する必要があります。

docker update --restart=always jenkins-docker

これにより、jenkins-dockerコンテナは常に実行状態に保たれます。

注意

プラグインを更新する際には、現在運用中のJenkinsのバージョンと互換性があるかどうかを慎重に確認してください。Jenkinsとプラグインのバージョンが一致しないと、パイプラインの失敗につながることがよくあります。

参考

Managing Jenkins with Docker

より直感的な 'diff' を実現する、Difftastic

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

概要

Difftasticは、git diffの使用をより便利にするためのツールです。ターミナルで頻繁にgit diffコマンドを使用する人にとって非常に役立ちます。

使用方法

brew install difftastic

グローバル設定:

git config --global diff.external difft

これで、git diffコマンドを使用すると、以前よりもはるかに直感的な差分結果を確認できます。

image

参考

有効な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

参考

キー生成エラー

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

ここにエラーを解決するための簡単な解決策があります。

key generation error: Unknown signature subpacket: 34

KeybaseでGPGキーを登録しようとした際に、上記のエラーが発生しました。解決策を探していると、GitHubで以下の回避策を見つけました。

$ gpg --edit-key mykey

gpg> showpref
[ultimate] (1). mykey
Cipher: AES256, AES192, AES, 3DES
AEAD: OCB, EAX
Digest: SHA512, SHA384, SHA256, SHA224, SHA1
Compression: ZLIB, BZIP2, ZIP, Uncompressed
Features: MDC, AEAD, Keyserver no-modify

gpg> setpref AES256 AES192 AES 3DES SHA512 SHA384 SHA256 SHA224 SHA1 ZLIB BZIP2 ZIP
Set preference list to:
Cipher: AES256, AES192, AES, 3DES
AEAD:
Digest: SHA512, SHA384, SHA256, SHA224, SHA1
Compression: ZLIB, BZIP2, ZIP, Uncompressed
Features: MDC, Keyserver no-modify
本当に設定を更新しますか? (y/N) y

gpg> save

これで操作がスムーズに進むはずです。詳細については、提供されたリンクを参照してください。

参考

Vimiumのショートカットを変更する方法

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

概要

最近、Vimを使い始めたので、すべての環境をVimに合わせるようにしています。その中で、Safari用のVim拡張機能であるVimariと、Chrome用の拡張機能であるVimiumのショートカットにいくつかの違いがあることに気付きました。それらを統一するために、特定のキーをリマップすることにしました。このガイドでは、Vimiumでショートカットをリマップする方法を紹介します。

Vimiumオプションウィンドウ

where

Chromeの拡張機能のボタンをクリックして、オプションを開きます。

input

このセクションを変更することで、ショートカットを変更できます。基本的なマッピング方法はVimと同じです。個人的には、Vimariのタブナビゲーションショートカットをq, wからVimiumのJ, Kに変更する方が便利だと感じました。

特定のアクションにどのキーをマップすれば良いか分からない場合は、その横にある「利用可能なコマンドを表示」をクリックすると、役立つ説明が表示されます。

help-view

ここから、希望するアクションを見つけて特定のキーにマップすることができます。

Macでキーボードのキーリピートを有効にする

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

Macでは、特定のキーをしばらく押し続けると、ウムラウトなどの特殊文字入力ウィンドウが表示されることがあります。これは、Vimのようなエディタでコードナビゲーションを行う際に非常に邪魔になることがあります。

defaults write -g ApplePressAndHoldEnabled -bool false

上記のコマンドを実行し、アプリケーションを再起動すると、ウムラウトなどの特殊文字入力ウィンドウが表示されなくなり、キーリピートが有効になります。

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コンテナにおけるデータ管理の重要なメカニズムです。コンテナの性質に応じて適切にボリュームを使用することで、データを安全かつ簡単に管理でき、慣れれば開発の生産性を大幅に向上させることができます。詳細な情報については、公式ドキュメント を参照してください。

参考文献

[Jacoco] マルチモジュールプロジェクトのためのJacocoレポートの集約

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

概要

Gradle 7.4から、複数のJacocoテストレポートを1つの統合レポートに集約する機能が追加されました。以前は、複数のモジュールにまたがるテスト結果を1つのファイルで見るのは非常に困難でしたが、今ではこれらのレポートを統合することが非常に便利になりました。

使用方法

レポートを収集するためのサブモジュールの作成

現在のプロジェクト構成は、applicationというモジュールと、applicationモジュールで使用されるlistutilsといった他のモジュールで構成されています。

code-coverage-reportモジュールを追加することで、applicationlistutilsモジュールからテストレポートを収集できます。

プロジェクト構成は次のようになります:

  • application
  • utils
  • list
  • code-coverage-report

jacoco-report-aggregationプラグインの追加

// code-coverage-report/build.gradle
plugins {
id 'base'
id 'jacoco-report-aggregation'
}

repositories {
mavenCentral()
}

dependencies {
jacocoAggregation project(":application")
}

これで、./gradlew testCodeCoverageReportを実行することで、すべてのモジュールのテスト結果を集約したJacocoレポートを生成できます。

jacoco-directory

警告

集約機能を使用するには、jarファイルが必要です。jar { enable = false }と設定している場合は、trueに変更する必要があります。

更新 22-09-28

Gradleのマルチプロジェクトセットアップの場合、単一プロジェクトで正しく除外されたパッケージが集約レポートでは除外されない問題があります。

次の設定を追加することで、特定のパッケージを除外したレポートを生成できます。

testCodeCoverageReport {
reports {
csv.required = true
xml.required = false
}
getClassDirectories().setFrom(files(
[project(':api'), project(':utils'), project(':core')].collect {
it.fileTree(dir: "${it.buildDir}/classes/java/main", exclude: [
'**/dto/**',
'**/config/**',
'**/output/**',
])
}
))
}

次のステップ

Gradleでjacoco-aggregation-reportと一緒に導入されたjvm-test-suiteプラグインも非常に有用です。これらのプラグインは補完的な関係にあるため、一緒に使用することをお勧めします。

参考