こんにちは!開発現場の裏側を支えるCI/CDパイプライン、毎日お疲れ様です。
「JenkinsでDockerイメージをビルドしたい!」と思ったとき、昔からよく使われてきたのがDocker in Docker (DinD)という手法です。Jenkinsのビルドエージェントの中でさらにDocker daemonを動かし、`docker build`を実行するというものですね。
しかし、このDinD、現場のインフラエンジニアやセキュリティ担当者にとっては悪夢のような技術です。
今回は、なぜDinDが危険なのか、そして現代のセキュアなCI/CDにおいてデファクトスタンダードになりつつある「Kaniko」をJenkinsに組み込み、安全かつ高速にコンテナをビルドする方法を、優しく丁寧に解説していきます。
これをマスターすれば、セキュリティの穴を塞ぎつつ、ビルダーとしてのパフォーマンスも劇的に向上しますよ。さあ、一緒に見ていきましょう!
—
1. なぜ「Docker in Docker (DinD)」はご法度なのか?
まずは敵を知ることから始めましょう。DinDの最大の問題点は、コンテナの中からホストのDocker daemonに特権(Privileged)アクセスする点にあります。
- セキュリティリスクの塊: DinDを動かすには、コンテナを `–privileged` モードで起動する必要があります。これは、コンテナとホストOSの間の隔離壁を実質的に取り払う行為であり、万が一コンテナが乗っ取られた場合、ホストOS(Jenkinsの実行基盤)の完全なコントロールを奪われることを意味します。
- キャッシュの共有が困難: ビルドのたびにコンテナがクリーンアップされるため、レイヤーキャッシュの効率が悪くなり、ビルドが毎回遅くなりがちです。
「手っ取り早く動くから」といってDinDを野放しにしていると、セキュリティ監査で必ず指摘を受けることになります。
2. 救世主「Kaniko」とは何か?
そこで登場するのが、Googleが開発したオープンソースツール 「Kaniko」 です。
Kanikoの最大の特徴は、「Docker daemonを一切使わずに、ユーザーランドでDockerfileを安全に解釈・実行してコンテナイメージをビルドする」という点にあります。
- root権限が不要: Linuxのネームスペースやroot権限を必要としないため、KubernetesのPod内やセキュアなコンテナ環境で安全に動作します。
- リモートレジストリとの直接連携: ビルドしたイメージをローカルのDocker daemonを経由せず、直接コンテナレジストリ(Docker Hub, GCR, Amazon ECRなど)にプッシュします。
JenkinsのPod(Kubernetesプラグインを使用している環境)や、Dockerがインストールされていない軽量なJenkinsエージェントでも、安全にコンテナビルドが行えるようになるのです。
—
3. 全体像:Jenkins × Kubernetes × Kaniko
今回は、現代のモダンなJenkins運用で最もポピュラーな「Kubernetesプラグインを使った動的エージェント(Pod)」上で、Kanikoを走らせるアーキテクチャを想定します。
大まかな流れは以下の通りです。
1. JenkinsがKubernetes上にビルド用Podを立ち上げる。
2. Pod内のコンテナとして、Kanikoのエグゼキューター(`gcr.io/kaniko-project/executor`)を配置する。
3. Gitからチェックアウトしたソースコードを元に、Kanikoがレイヤーを構築。
4. Docker daemonを介さず、直接レジストリへイメージをプッシュ!
—
4. 実践!セキュアなJenkinsfileの構築
それでは、実際にKanikoを使ったDeclarative Pipelineのコードを見ていきましょう。
「HelloWorld」のステップとして、シンプルなDockerfileをビルドしてコンテナレジストリへ送るまでの構成を解説します。
レジストリ認証情報の準備
Kanikoがレジストリ(例:Docker HubやAmazon ECR)にプッシュするためには認証が必要です。Docker Hubの場合、Jenkinsの「認証情報(Credentials)」に登録したユーザー名とパスワードを、KubernetesのSecret等経由でKanikoに渡すか、あるいはKaniko専用の `config.json` を作成して渡します。
今回は最も一般的な、JSONファイルによる認証情報のマウント方式を前提としたJenkinsfileを見てみましょう。
pipeline {
agent {
kubernetes {
yaml ”’
apiVersion: v1
kind: Pod
metadata:
name: kaniko-builder
spec:
containers:
# 1. Kanikoのエグゼキューターコンテナの定義
- name: kaniko
image: gcr.io/kaniko-project/executor:v1.14.0-debug
command:
- /busybox/cat
tty: true
# root権限は不要ですが、セキュリティコンテキストで安全性を担保
securityContext:
runAsUser: 0
volumeMounts:
# レジストリの認証情報をマウント
- name: docker-config
mountPath: /kaniko/.docker
volumes:
- name: docker-config
secret:
secretName: regcred # Kubernetes側に作成したレジストリ認証用Secret
”’
}
}
stages {
// ステップ1: ソースコードの取得
stage(‘Checkout’) {
steps {
checkout scm
}
}
// ステップ2: Kanikoによるビルド&プッシュ
stage(‘Build and Push with Kaniko’) {
steps {
container(‘kaniko’) {
sh ”’
echo “Kanikoによるセキュアなビルドを開始します…”
/kaniko/executor \\
–context=dir://${WORKSPACE} \\
–dockerfile=Dockerfile \\
–destination=my-docker-registry.example.com/my-team/my-app:${BUILD_NUMBER} \\
–destination=my-docker-registry.example.com/my-team/my-app:latest \\
–cache=true
echo “ビルドとプッシュが完了しました!”
”’
}
}
}
}
post {
always {
cleanWs()
}
}
}
5. コードのここがポイント!解説とハック
上記のJenkinsfileとKanikoのコマンドライン引数には、現場で役立つ重要なポイントが詰まっています。
1. `gcr.io/kaniko-project/executor:v1.14.0-debug` の利用
末尾に `-debug` がついたイメージを使用している点に注目してください。このイメージには `/busybox/sh` やシェルが含まれているため、JenkinsのKubernetesプラグインがコンテナを起動する際のコマンドエントリポイントとしてスムーズに連携できます(通常のイミュータブルな本番用Kanikoイメージだとシェルが入っていなくてハマることがよくあります)。
2. `–context=dir://${WORKSPACE}`
Jenkinsがチェックアウトしたワークスペースのパスを指定しています。KanikoはローカルのディレクトリやS3バケット、Gitリポジトリなどを直接ビルドコンテキストとして指定できます。
3. `–cache=true` による高速化の恩恵
Kanikoは、ビルドしたレイヤーをリモートレジストリにキャッシュとして保存・参照する機能を持っています。これにより、DinDを使わなくても「前回のレイヤーを再利用してビルドを爆速化する」という恩恵をそのまま受けることができます。
—
おわりに:安全で快適なCI/CDの世界へ
いかがでしたでしょうか?
今回は、JenkinsとKanikoを連携させ、Docker in Dockerというセキュリティ上の爆弾を回避しながら、安全かつ高速にコンテナイメージをビルドする手法をご紹介しました。
- root権限不要で動作するため、インフラチームからも文句なしの太鼓判を押される。
- 余計なデーモン管理が不要なため、CI/CDパイプライン全体が非常に軽量で安定する。
これを一度導入すれば、もう二度と「DinDが死んだ」「権限エラーでビルドが止まった」というトラブルシューティングに悩まされることはなくなります。
あなたの毎日の開発・運用作業が、より安全で、劇的に楽になることを応援しています!