とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど
読者登録と各種SNSのフォローもよろしくお願いいたします。

イベントレポート 第21回とことんDevOps勉強会「今さら聞けないDocker入門 〜Dockerfileのベストプラクティス編」

今回のとことんDevOps勉強会は「今さら聞けないDocker入門 〜Dockerfileのベストプラクティス編」と題して、日本仮想化技術の水野が、Dockerの基本とDockerfileのベストプラクティスについて紹介しました。

Dockerは、コンテナ化技術を提供するプラットフォームで、アプリケーションやサービスを独立した環境で動かすことができます。コンテナ化することで可搬性が高くなり開発から本番環境まで一貫性のある動作が可能になります。また、チーム内で開発環境の共有もしやすくなります。

振り返りも兼ねて当日の配信の様子をYouTubeでアーカイブしていますので、是非ご覧ください。当日参加できなかった方も、これを機会にとことんDevOps勉強会に興味を持っていただければと思います。また、当日いただいたQ&Aに関してもこちらのブログでまとめていますので、ぜひご覧ください。

セミナー動画

www.youtube.com

発表資料

speakerdeck.com

Q&A まとめ

Dockerfile内で/var/libapt/list/*内を削除するのは何でですか?

Dockerfile内で/var/lib/apt/lists/*を削除するのは、イメージのサイズを最小限に抑えるためです。 apt-getコマンドがパッケージのリストをキャッシュしますが、これはパッケージをインストールし終わった後は不要な情報です。これらのキャッシュは、イメージのサイズを大きくする原因になります。パッケージをインストールした後にパッケージリストを削除することで、最終的なイメージのサイズをより小さくすることができます。

クレデンシャルはどこに保持するべきでしょうか?

利用方法によって異なりますが、CI/CDなどの自動化を考慮したシステムでは、AWSのシークレットマネージャーやHashiCorpのVaultなど、安全にシークレットを管理する仕組みを利用することが望ましいです。また、ローカル環境でのみ使用する場合は、envファイルなどのメカニズムを活用して、コンテナ起動時に環境変数として読み込むと便利です。

C/C++ライブラリ のパッケージ管理方法(Win, Unixのマルチプラットフォーム)デバッグ版の扱い。Dependency Graphはどうするか?

デバッグ用のコンテナとそれ以外のコンテナを分けると、管理がしやすくなるかもしれませんね。その他の質問については、今回はお力になれませんでした。

C/C++コードのパッケージ管理とSCM管理について知りたいです

参加者からの情報によると、Conanを使用するとC/C++のパッケージ管理が便利そうです。

Conan 2.0: C and C++ Open Source Package Manager

同じコンテナでphpの開発環境、本番環境を作る場合、Xdebugの取り扱いに困ります。うまい方法があれば知りたいです

本番環境と開発環境では、コンテナに求められる条件が異なることがあります。一つのDockerfileで複雑な設定を行うことも可能ですが、可読性や保守性の観点からはトレードオフが生じる可能性があります。DRYの原則に反することになりますが、現時点では本番環境用と開発環境用のコンテナを分けて作成する方が望ましいかもしれません また、他にも環境変数などを活用したフラグ方式やマルチステージビルドを活用した方法などもありますので、調べてみてはいかがでしょうか。

DockerfileにもLinter/Formatterがあると思いますが、使われていますか?

弊社ではhadolintというツールを使用しています。他にもVisual Studio Codeの拡張機能など、さまざまなツールが提供されていますので、ぜひ試してみて、自分に合ったものを見つけてみてください。

GitHub - hadolint/hadolint: Dockerfile linter, validate inline bash, written in Haskell

Dockerfileの中でOSイメージやライブラリで:latest を指定する事があるかと思いますが、バージョン依存や破壊的な変更が加わる場合もあるので、全てライブラリ等のバージョン指定をした方が良いと思いますが、どうでしょうか?可搬性を謳うのであれば。

はい、できればバージョン指定を細かく設定できるといいですね。 例えば、分散型の環境では、同じコンテナを複数のインスタンスで実行している場合、新しく立ち上げたり再起動したりすると、バージョンが変わることがあります。

パッケージ管理ツールconanのGitHubやDevOpsとの親和性、

参加者からの情報によると、Conanを使用するとC/C++のパッケージ管理が便利そうです。

Conan 2.0: C and C++ Open Source Package Manager

DockerのWIndowsコンテナとUnixコンテナの共存や利用方法

Windowsコンテナを実行するにはWindows(Hyper-V)が必要になるため、最初からそれを考慮して環境を構築する必要があります。

VSCode DevContainerを標準にする方法

使い始めると便利なツールではありますが、開発において重要な役割を果たすため、一部の人々は漠然とした不安を感じたり、試した際に不快な体験をしたりしています。そのため、導入に対する様子見のニーズが強いようです。不安を克服することは、重要な転換点と考えられますが、メインの開発に直ちに導入するのではなく、レビューやその他の間接的な手段を通じて試し、不安を軽減する時間を取ることが重要だと感じます。

IBMがHashCorpを買収した場合どうなるのか。

あまり詳しい情報は持ち合わせていませんが、目下では大きな影響が出るとは考えていません。

DockerでWindowsイメージを使うときの、ライセンスの考え方はどうなりますか。費用はどのくらいでしょうか。

下記リンクの情報が参考になると思いますので、ぜひご覧ください。 https://learn.microsoft.com/ja-jp/virtualization/windowscontainers/about/faq

Dockerfileの中でOSイメージ等をインターネット接続ありきで取得する想定が多いと思います。ネット障害やそもそも公式が提供しなくなる等のリスクがあると思います。ローカルリソースを取得先にするのはどうでしょうか?

ネットワーク障害や公式のDockerイメージが提供されないリスクは確かにありますね。特に本番環境などで使用する場合、自分たちの環境にイメージをキャッシュしておくことは合理的な考え方です。イメージはdocker saveを使用してすべて保存できますし、Dockerレジストリと呼ばれるサービスも利用できるので、別途保持しておくと便利ですね。

オンプレのサーバ1台に環境構築したらほぼ変更がないような場合でもDockerコンテナを使うメリットはありますか?構築後はOSのアップデートくらいしか行わないなら、VMとかのほうがふさわしいでしょうか?

すべてのサーバーに、必ずしもコンテナ化のメリットがあるとは限りませんね。ケースバイケースですが、例えばファイルサーバーのSambaなどは、コンテナ化する意味はたぶんないでしょう。

WIndowsとLinuxコンテナを同時に立ち上げる方法はありますか?

先ほども述べたように、Windowsコンテナを実行するには、ホストOSがWindowsである必要があります。

DBをdocker上にインストールすることはコンテナを使い捨てにするという点でアンチパターンに当たりますか?

コンテナは本質的に揮発性のものです。対してDBは永続的なデータを前提としているサーバーですが、DBのエンジン自体をコンテナとして起動すること自体は、アンチパターンではありません。とはいえ何らかの方法でデータを永続化する仕組みを用意する必要があります。例えばDockerならVolumeを活用するなど、データの永続化方法については検討の余地があります。

外部サービスとして公開する場合に、ある機能はコンテナ、別の機能はVM上に構築するといったハイブリッド構成もありえるんでしょうか?例えば、Webアプリ部はコンテナ、データベース部はVM上に直接実装など

はい、そういうこともありますね。 たとえば、AWSなどのクラウドサービスを利用していて、ECSやEKSなどでアプリケーションを実行し、データベースはRDSなどのマネージドサービスを使うことが一般的です。 ご質問のように、直接VM上に構築することもできますが、パフォーマンス要件などを満たすかどうかを検証してから導入を進めることが望ましいと思います。

ベースOSにデフォルトで含まれるaptパッケージの脆弱性チェックはどうやって行いますか。

レポートなどが必要な場合は、脆弱性チェックツールのサービスを利用してください。 ベースOSなどに脆弱性が見つかった場合、通常はバージョンアップするしかありませんので、見つかった脆弱性に対処するためには最新バージョンに更新してください。

Dockerコンテナのリソース監視はどのようにしていますか?イニシエはcAdvisorなどでしたが。

Dockerコンテナのリソース監視について、EKSクラスターを使用しているため、監視ツール(CloudWatch)や監視SaaS(Datadogなど)を利用しています。 各コンテナのリソースを過度に監視する必要はないと考えています。代わりに、コンテナを複数台起動して冗長性を確保したり、負荷の変動に応じて自動的にコンテナの数を調整する自動化などを検討することが重要かもしれません。

latestや特権ユーザなどをつかわせなくするようなルールを強制することをできますか?(このような設定がされているとデプロイできなくするなど)

AWSのECRなどではlatestタグを禁止する設定も可能ですね。 自力で行う場合、CI/CD上でチェック機能を実装するか、GitHubの機能を活用して、特定のファイルの変更に関してはレビューリーダーを指定し、その人のレビューが通らないとマージできないような仕組みを活用することができます。

dependabotやrenovateを有効にしている場合でもコンテナのイメージスキャンをやった方がいいのでしょうか?

可能であれば、実施しておくことをおすすめします。 ビルドの過程でCI/CDに組み込んで、自動的に実行されるようにするのも良いでしょう。

CI/CDパイプラインを構築するところまでは進められるが、文化として根付かせていくところで苦戦しています。どのように現状を打開したらよいか悩んでいます。

DevOpsは組織文化の構築から始まるため、最も難しい部分ですね。 CI/CDパイプラインがすでに構築されている場合、その担当者がメンテナンスを行い、他のメンバーが利用する形が望ましいと考えます。 同時に、ワンオペ状態を解消するために、もう1人担当者を増やしていくことが現実的な方法です。 また、他のチームや組織に展開していく際も、着実に1人ずつ拡大していくことが重要です。

dockerのデフォルトのkill signalでkillできないimageを実行されることがありますが、なにか指定する方法はありますでしょうか(compose、k8sなどで)?

コンテナ内で複数のプロセスを実行している場合、プロセスが正常に終了しない場合があるかもしれません。 kill方法を探る前に、まずはコンテナの設定やDockerfileの書き方などを調査してみると良いでしょう。

レイヤーキャッシュで思い通りに動かなくなるのはどういうケースでしょうか?パッケージのバージョンが上がってるとか?

スライドの例では、apt-get updateとapt-get installをまとめて書いていましたが、これらを別々に書くことで意図しない動作になる場合があります。 例えばapt-get updateを独立した行に書いており、その後にapt-get install hogeという行を追加したとしましょう。この際、apt-get updateの行は書き換えられていないため、キャッシュが再利用されます。ですがキャッシュ作成時よりも後に、hogeパッケージのバージョンが更新されていた場合、古いキャッシュが使われることで最新のパッケージを取得できず、インストールに失敗するといったケースが考えられます。

ciでのtrivyのスキャンとイメージリポジトリのスキャンどちらか有効にしておけば問題ないのでしょうか?trivyだと漏れがある場合などがあるのか気になりました。

脆弱性スキャンサービスは、一般的にはOVALと呼ばれる脆弱性情報を利用しています。配信元が同じであれば、最低限の部分では大きな違いはないと思います。

社内でDevOpsの理解が浸透しておらず、特に意思決定者の説得に苦戦しています。何か良い方法などないでしょうか。

難しい質問ですが、意思決定権を得るのはかなり難易度が高いですね。現場で小規模な取り組みを行いながら進めてみることが有益かもしれません。DevOpsで使われる技術は一般的にも広く利用されていますので、他の理由を探って説得することで、進めやすくなるかもしれません。

docker-composeって、いつ実行すればよいのでしょうか?

Composeを使いたい時に利用してください。 ちなみに、"docker-compose"というコマンドは古い記法ですので、新しい書き方に切り替えることをお勧めします。

DockerfileのFROMで参照されるimageが変更された場合、キャッシュは利用されますでしょうか?例えば、docker pull python:3 を指定したときに、docker hub上で参照されるイメージが変更されたとき、キャッシュを無視してdocker hubからpullされますでしょうか?

はい、FROMで指定しているイメージが変更されると、キャッシュは無視されて再取得されます。

Dockerの最新の費用面について伺いたいです。

dockerコマンド自体には料金はかかりませんが、Docker DesktopやDocker Hubを利用する際には、一定の条件を満たす場合に利用制限や有料プランの契約が必要です。 詳細については、Docker公式の料金体系をご確認いただくか、Dockerの問い合わせ窓口に直接連絡いただくことをお勧めします。 https://www.docker.com/ja-jp/pricing/

DockerHubはどのくらい活用するのか

公式のレジストリであるため、大抵のケースではDockerHubを利用することになるでしょう。ただしレートリミットがあるので、使用量には注意してください。

「クレデンシャルはどこに保持するべきでしょうか?」の質問の類似ですが、環境変数やファイルにクレデンシャルを入れてしまうとサーバに侵入されたときに、漏れてしまうと思っています。k8sなどで簡易的な暗号化はできると思いますが、社内のインフラの制約で実行できず、どこに入れようか悩んでいます。

ローカル開発の場合は、envファイルを活用すると便利ですが、クラウド環境ではシークレットマネージャーを利用するのが良いです。 また、Vaultなどのシークレット管理サービスとの連携方法もあります。

1つのアプリ開発ができる環境を1つのDockerコンテナで構築する場合、アプリケーションが動作する環境を構築するか、コーディング作業もできる開発までできる環境を構築するかを悩んでいます。どのような観点で判断すればよいのでしょうか?

本番から開発環境までのオールインワンの環境にまとめるのは難しいことですね。どのようにまとめるか迷うことはよくあります。 コンテナ環境を準備する際に、ボトルネックや時間の負担が大きい場合は、一度個別に分けてから運用を開始するのも良いかもしれません。 また、知識やスキルが身についてきたら、開発環境用に別途構築し、本番用のイメージをビルドする際に工夫する方法も1つのアイデアですね。

一般用語だとコンテナは入れ物なので、コンテナからイメージをつくるイメージなんですけど、Dockerの場合は逆なんですよねー。。。この辺は皆さんはあまり違和感は感じない❓

コンテナイメージとコンテナインスタンスは、コンテナの概念です。イメージからインスタンスを作ると考えると理解しやすいかもしれませんね。

KVM、LXC、Dockerコンテナはどう使い分けるのがいいですか?

KVMは、仮想マシンを作成するためのツールで、VM的な使い方をします。 LXCは、カーネル以外の部分を丸ごと動かすシステムコンテナを得意としています。軽量なVM感覚でコンテナを運用できます。 Dockerは、アプリケーションの実行環境を簡単に構築したい時に使用します。

Dockerの最新の費用面について伺いたいです。

Dockerの料金については、以下のサイトを参考にしてみてください。 https://www.docker.com/ja-jp/pricing/

おわり

今回は参加者も多く参加いただき、コメントも盛り盛り上がった回になりました。Dockerを使ったコンテナ開発を始めるためのきっかけになれば嬉しいです。本勉強会では、これからも皆さんの学習や現場の困りごと解決につながるようなテーマで開催できるように企画中です。次回のご参加をお待ちしております。

また、DevOpsの始め方に困った時には、無料相談会を有効にご活用ください。