本記事は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 やはり業務を通して(にゃーん↩