本記事はAnsible Advent Calendar 2021の14日目のエントリです。
珍しくインプットが湧いてきた1ため2日連続です笑
環境その他もろもろは、以前Ansible Builderについて試したこの記事のときのものと同じです。
解決したい課題
7月に一度、新しいAnsibleの実行環境であるExecution Environment(以下EE)をお試し実行してみましたが、この時「OSパッケージインストール周りでリポジトリ追加したい場合なんかは現状不明。」という課題を残したまま放置してました。
当時は「イメージ内に追加で必要なパッケージはbindep.txtに記述する」機能から発想が縛られて、「一度ビルドを実行すると生成されるcontext/Containerfileファイルがあるため、内容を書き換えて(as builderの後にリポジトリを追加する処理を差し込む)リビルド」というかなり無理やりなことをしていました。
というのも、EEの定義ファイル(デフォルトexecution-environment.yml)にパッケージインストール関連で記載できるのはbindep.txtにパッケージ名、あとリポジトリの変更を行いたければadditional_build_steps以下に記載はできるけど、肝心の処理順序が「bindepによるパッケージインストール」が先で、「additional_build_stepsのprependの処理」が後(※)のため、bindep.txtにリポジトリ追加が必要なパッケージを記載しても、そのリポジトリ追加を行うタイミングが無い、というモノでした。(鶏卵 ちょっと違うか…)
※12/14夜追記: 正確には、イメージビルドの内訳として、builderのイメージビルド(FROM $EE_BUILDER_IMAGE as builderの部分)と、runnerのイメージビルド(FROM $EE_BASE_IMAGEの部分)があり、最後のrunnerのイメージビルドはadditional_build_stepsに記述した処理のあとにbindep.txtを参照したパッケージインストールが行われるので期待通りの動きをするが、中間にあるbuilderのイメージビルドはadditional_build_stepsの処理は行わずにbindep.txtを使ったパッケージインストールを行う処理内容になっている。詳細はビルド時に生成されるContainerfileを参照。
ですね。言い方変えるとrunnerとbuilderそれぞれカスタムイメージをビルドしててどちらもbindep参照してるけど、prependの処理が入るのはrunnerのビルドだけ、という構成でした。
— z a k i 🌈🌉 (@zaki_hmkc) 2021年12月14日
回避策
実際のところ、Execution Environment Definitionを見ても、リポジトリ設定の余地は現状ないので、機能的には無さそう。
ansible-builder.readthedocs.io
ただ、そもそも7月の時点でどうして思いつかなかったんだ、というレベルだったりするけど、additional_build_stepsの中で、
をどちらも書いてしまえばいいじゃん、というのを思いついたのでお試し。
お題は前回と同じくKubernetesのCLIコマンドのインストール。
execution-environment.yml (抜粋)
additional_build_stepsの部分は以下の通り。
additional_build_steps: prepend: - COPY kubernetes.repo /etc/yum.repos.d/kubernetes.repo - RUN dnf install -y kubectl
Kubernetesのドキュメントではcatとヒアドキュメントでファイル生成してるけど、ちょっとコツがいるので素直に外部ファイル化してCOPY使っている。
(これはこれでコツがいるんだけど…後述)
なお、EEのベースイメージはCentOSベースなので、パッケージもCentOSの場合の手順を実施。
kubernetes.repo (追加ファイル)
これはドキュメントの通りの内容。
インライン記載は後述してるけど、別途ファイル用意した方が(今回の場合は)ミスは少ないと思う。
[kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
ビルド
execution-environment.ymlなどの制御に使用するファイル以外の、イメージ内部に追加したい(今回のkubernetes.repoファイルのような)追加ファイルがある場合は、ビルド時にコンテキストの指定が必要。
$ ansible-builder build --help
[...]
-c BUILD_CONTEXT, --context BUILD_CONTEXT
The directory to use for the build context (default: context)
これはデフォルドではcontextというディレクトリが指定されるが、このディレクトリがビルド時のルートディレクトリとして扱われるイメージ。もっといえば、ここがchrootされる感じ。
つまり、イメージへ追加したいファイルがある場合は、コンテキストで指定したディレクトリ以下になければ、ビルド時にファイルを(例えフルパスで指定してたとしても、ビルド時のルートはコンテキストで指定したディレクトリになるため)認識できない。
よって、具体的なコマンドラインは、execution-environment.ymlやkubernetes.repoのあるディレクトリで以下の通り。
$ ls -F Containerfile bindep.txt kubernetes.repo requirements.yml ansible.cfg execution-environment.yml requirements.txt $ ansible-builder build --tag kube-sample:devel --context .
これで、イメージビルド時のCOPYの対象であるkubernetes.repoを認識してイメージへコピーできるようになる。
ファイル数が多く、execution-environment.ymlなどとは分離したい場合は、「イメージへ組み込みたいファイル用のディレクトリを作成し、--contextでそのディレクトリを指定」すればOK.
その場合でも、COPYの引数に指定するファイルのパスは、--contextで指定するディレクトリ基準の相対パスにすれば良い。
確認
$ ansible-builder build --tag kube-sample:devel --context files Running command: podman build -f files/Containerfile -t kube-sample:devel files Complete! The build context can be found at: /home/zaki/ee/kube/files $ podman run -it --rm localhost/kube-sample:devel bash bash-4.4# cat /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg bash-4.4# kubectl version --short --client Client Version: v1.23.0
ちゃんとできている。
ヒアドキュメントは…無理かな?
これはダメだった例。
prepend: | COPY <<EOF /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg EOF
これはワンチャン行けるかなと思ったけど、構文エラーにはならずビルドは動いて、COPYのタイミングで「<<EOFというファイルが無い」というエラーとなった。
STEP 17: COPY <<EOF /etc/yum.repos.d/kubernetes.repo Error: error building at STEP "COPY <<EOF /etc/yum.repos.d/kubernetes.repo": checking on sources under "/home/zaki/ee/kube/context": copier: stat: "/<<EOF": no such file or directory
インラインでやるならこんな感じ。
echoに-eオプションを付加し、\nで改行しつつ、行末の\で次行へ続ける記述でファイル作成を確認。
prepend: | RUN echo -e "[kubernetes]\n\ name=Kubernetes\n\ baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64\n\ enabled=1\n\ gpgcheck=1\n\ repo_gpgcheck=1\n\ gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg" > /etc/yum.repos.d/kubernetes.repo RUN dnf install -y kubectl
確認した環境
$ cat /etc/redhat-release Fedora release 34 (Thirty Four) $ ansible-builder --version 1.0.1 $ python --version Python 3.9.4
おまけというか備忘録
additional_build_steps以下prependへのコマンドの指定は、リストでも複数行テキストでもどっちでもOKでした。
-
同じシチュエーションの対応策に困ってる部署のメンバがいて、回避策を偶然思いついた、というものw やはり業務を通して(にゃーん↩