こんにちは。InflabのDevOps EngineerのSunBです!
今回は、Dockerを扱う中で見つけた、Alpineベースのイメージのcpコマンドと、DebianまたはUbuntuベースのイメージのcpコマンドの挙動の違いをご紹介します。
Docker Image
Dockerでは、Imageを使ってContainerを作成できます。
Docker ImageはLayerで構成されており、Base Imageに対してコマンドを実行したり、外部からファイルをコピーしたりしてLayerを追加することで、新しいImageをビルドできます。
ビルドに使われたDockerfileを開いてみたり、node:gallium-alpine のように作成者が付けたTagを参考にしたり、実際に実行してインストールされているパッケージマネージャーが何かといった特性を調べたりすることで、ビルドされたイメージのBase Imageにどのイメージが使われたかを推測できます。
Base Imageとしては、容量が非常に小さいという利点を持つAlpineイメージと、汎用的なDebianおよびUbuntuイメージがよく使われています。
本記事では、Alpineベースのイメージを使っていたところ、互換性の問題を解決するためにDebianベースへ移行する際に見つけた注意点についてお話しします。
Alpine
alpine:latest、node:alpine のようなAlpineベースのDocker Imageで、以下のコマンドを実行してみましょう。
echo 1 > a
echo 2 > b
ln -s a c
cat a b c
結果は以下のようになるはずです。
1
2
1
次に、以下のコマンドでcpコマンドの挙動を確認してみましょう。
cp b c
cat a b c
結果は以下のとおりです。
1
2
2
確認してみると、作成したシンボリックリンクは削除され、ファイルbがcという名前でコピーされたことが分かります。
DebianまたはUbuntu
debian:latest、ubuntu:latest、node:latest のようなDebianまたはUbuntuベースのDocker Imageで、同じコマンドを実行してみましょう。
echo 1 > a
echo 2 > b
ln -s a c
cat a b c
結果は以下のようになるはずです。
1
2
1
次に、以下のコマンドでcpコマンドの挙動を確認してみましょう。
cp b c
cat a b c
結果は以下のとおりです。
2
2
2
驚いたことに、シンボリックリンクは削除されず、ファイルbの内容だけがシンボリックリンクcにコピーされた結果、ファイルaの内容が変更されてしまったことが分かります。
Alpineイメージと同じ結果を得たい場合は、cp b c コマンドを実行する前に rm c コマンドを実行して、シンボリックリンクを明示的に削除する必要があります。
2つのイメージをまたぐマイグレーション作業を行う場合は、こうした違いを把握したうえで、適切にコマンドを修正する必要があります。
おわりに
この現象を見つけたあとチームメンバーに共有したところ、バックエンド開発者のINTさんの協力を得て、cpコマンドにaliasが設定されていないか確認してみましたが、aliasは設定されていませんでした。
検索してもこれといった情報は得られなかったので、この現象の原因をご存じの方がいらっしゃいましたら、コメントで教えていただけると大変ありがたいです!
ありがとうございました。