【例えて解説シリーズ】コンテナの基本を『ハンバーガーチェーン』に例えて解説してみる

# このシリーズの目的と免責事項
本シリーズでは、主にIT業界で登場する様々なテクノロジーや技術を、**なるべく平易な事柄に例えて解説することで、多くの方が「なるほど！」と思える**よう試みます。

どうしてそのようなことをする必要があるかと言われれば、著者の業務である技術インストラクターという仕事上、**難しい事柄をいかに簡単なものに置き換えるか**ということは学びにおいて大変重要だと考えています。

一言だけ前置いておきたいのは、**極力一般的に伝わりやすい事柄を取り上げているつもり**ではあるのですが、やはりどう頑張っても全ての人の共感を得ることが難しい場合があるため、当記事をご覧いただいてから『いやいや、この例えはおかしいでしょ』とか『かえってわかりづらい』なんていう方もいるかもしれませんが、多めに見ていただけると幸いです。

## この記事でカバー”すること"と"しないこと"
この記事では、著者が主観的にコンテナにまつわる基本的な専門用語や基礎知識だと感じるものを、例え話を通じて説明します。そのため、1つ1つの製品やソフトウェアを掘り下げて解決は行いません。

基本的に主観に基づいて『コンテナの基本』と線引きをしているため、みる人によっては範囲が広すぎたり、狭すぎたり、異質に見える場合もあるかもしれません。その時はぜひ、コメント欄などで『これも追加してみては？』とコメントを頂ければ項目の追加を検討したいと思います。

## 今回の例え『ハンバーガーチェーン』
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/9c521734-69fd-449f-b9f5-3cd31f04f99d.png" width="300">

我ながら物凄くピンポイントに攻めた例えだなと思いながら記述しています。
数ある例えシナリオがある中で、あえてこうしたピンポイントなビジネスを選んだのには理由があります。

ハンバーガーチェーン店で買い物をしたことがある人は多いはず。
日本全国あるいは世界規模でビジネスを広げる企業もある中、どの店舗に行っても概ね同じメニューを選ぶことができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/fc53e2ee-11d8-4782-8e46-e25369e6a11c.png" width="300">

ハンバーガーに関して言えば、バンズと呼ばれるパンや中のトッピングに使われる野菜やビーフ、チキンなどを多彩に組み合わせることで色々なメニューを作ることができます。

こうした諸所のハンバーガーチェーンにある要素は、実はコンテナ環境で取り扱う基本的な用語や考え方と大変近いものがあると考え、この記事の作成に至りました。

それでは早速どのような点が似ているか掘り下げていきましょう。

## コンテナを学ぶ際に出てくる主要な用語たち

### チェーン店で調理をするスタッフ＝コンテナエンジンとコンテナランタイム
調理の現場では、多くのオーダーに対応するため役割分担をしていることでしょう。
コンテナの世界でも、コンテナエンジンとコンテナランタイムという主要な2つの要素があるおかげで、コンテナが実行できるので、早速その2つについてみていきましょう。

#### チェーン店を仕切る店長＝コンテナエンジン

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/d360c4fd-b726-4707-aa5b-2c33e389cdec.png">

**『オーダーが来たので、⚪︎⚪︎バーガーを1つ作ってください』**(podman run イメージ名)
**『本部から新しいメニューが発表されたので、みなさん調理方法を覚えてください』**(podman pull)
**『このメニューは廃止になりましたので、作らないでください』**(podman rmi)

こんな風に調理の現場への指示を出す役割がコンテナの世界にも存在しており、これがコンテナエンジンです。

コンテナエンジンの具体例としては、**Podman** や **Docker** といったソフトウェアがそれに該当します。
コンテナの勉強を始めると、必ずと言っていいほどこれらと出会うことになるでしょう。

これらのソフトウェアを使用すると、**podman run** や **podman build**（docker run, docker build）のようなコマンドを実行することになりますが、これがまさに店長による指示のようなものです。

いくつか有名なコンテナランタイム（と関連ツール）のリンクを以下に置いておきます。

https://podman.io/

https://www.docker.com/

https://containerd.io/

https://cri-o.io/

一般的にはコマンドラインベースで利用することが多いコンテナエンジンですが、GUIから操作することが出来る関連ツールもあります。

https://podman-desktop.io/

https://docs.docker.com/desktop/


なお、これ以降は著者である私が業務の性質上Podmanを使用する機会が多いため、諸所に登場するコマンドはすべてPodmanに統一して解説します。

#### 店長の指示を受け、実際の調理を行うスタッフ＝コンテナランタイム
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/770dcd52-469f-4fa4-8f19-161b53ab0f78.png">

上記のように、**店長の命令を受けて『調理をする』スタッフ**も必要です。
コンテナで言えば、コンテナを起動、停止、削除などのアクションが調理に相当すると考えてみてください。

やや極端な例えになりますが、コンテナランタイムは切る、焼く、煮るなどのシンプルな作業しかできない担当者のような存在です。

具体的なランタイムとしては、**runc** や **crun**、**containerd** などが有名です。
これらは、**Linux カーネル機能（cgroups や namespaces など）を使ってコンテナの実行を担当**します。

調理現場で言えば、レシピ通りに食材を切ったり、焼いたり、スープを煮込んだりするスタッフが、コンテナランタイムに相当します。

コンテナエンジンが、コンテナランタイムに対して **「このコンテナイメージを新しく追加したよ、このコンテナイメージを使ってコンテナを起動してね。あとそのコンテナはネットワーク⚪︎⚪︎に接続してね」** という指示を出すことで、ランタイムだけではできない細かい作業が実行可能になります。

このように、コンテナエンジンとコンテナランタイムは一緒に働いて、コンテナという「料理」を作り上げます。

##### コンテナエンジンが使用しているコンテナランタイムを確認してみた
podman infoコマンドの出力から、使用されているコンテナランタイムを確認してみました。
後半のociRuntime:の箇所以降が当該箇所となっています。
※出力がとても長いので、後半はカットしています。

~~~zsh: podman infoを実行してみた
yasakai@yasakai-mac lab8010-web % podman info                  
host:
  arch: arm64
  buildahVersion: 1.37.5
  cgroupControllers:
  - cpuset
  - cpu
  - io
  - memory
  - pids
  - rdma
  - misc
  cgroupManager: systemd
  cgroupVersion: v2
  conmon:
    package: conmon-2.1.12-2.fc40.aarch64
    path: /usr/bin/conmon
    version: 'conmon version 2.1.12, commit: '
  cpuUtilization:
    idlePercent: 99.86
    systemPercent: 0.07
    userPercent: 0.07
  cpus: 6
  databaseBackend: sqlite
  distribution:
    distribution: fedora
    variant: coreos
    version: "40"
  eventLogger: journald
  freeLocks: 2037
  hostname: localhost.localdomain
  idMappings:
    gidmap: null
    uidmap: null
  kernel: 6.11.3-200.fc40.aarch64
  linkmode: dynamic
  logDriver: journald
  memFree: 2473660416
  memTotal: 3792564224
  networkBackend: netavark
  networkBackendInfo:
    backend: netavark
    dns:
      package: aardvark-dns-1.12.2-2.fc40.aarch64
      path: /usr/libexec/podman/aardvark-dns
      version: aardvark-dns 1.12.2
    package: netavark-1.12.2-1.fc40.aarch64
    path: /usr/libexec/podman/netavark
    version: netavark 1.12.2
  ociRuntime:  #この行以降が使用されているランタイムに関する情報
    name: crun
    package: crun-1.17-1.fc40.aarch64
    path: /usr/bin/crun
    version: |-
      crun version 1.17
      commit: 000fa0d4eeed8938301f3bcf8206405315bc1017
      rundir: /run/crun
      spec: 1.0.0
      +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +LIBKRUN +WASM:wasmedge +YAJL

# 以下省略...
~~~

### 開発中のハンバーガーのレシピ＝コンテナファイル
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/9881ea3a-cbeb-41af-8513-1efb0be37b97.png">


各ハンバーガーチェーン店では、日々レシピの開発が行われていることでしょう。
アイデアを出し、試作品を作って、改良を加えているわけです。

実際のハンバーガーを作る場合も**素材の組み合わせや加工方法**を考えるはずです。
『やっぱりベースは定番のバンズにしよう』
『メインの具材はハンバーガーにしよう、調理方法は炭火で焼いてみようか』
『ソースにはケチャップベースのものにしよう』

**開発中なので、失敗する場合もあります。そのような場合は修正をする必要があります。**

コンテナの世界でも、Containerfile(またはDockerfile)の中に、『どんな構成にしようか』と考えながら必要な要素を記述していきます。この際、上から書かれたものから順番に処理が行われますので順番は重要です。
コンテナファイルも、記述された内容では不十分な場合は修正を行います。

こちらが実際に書かれたContainerfileのサンプルです。
※なお、Dockerfileと呼ばれる場合もあります
※Containerfileはviやvimをはじめとする一般的なテキストエディタで記述をいただけます。

~~~zsh: Containerfileのサンプル (この5行を含むテキストファイルを作れば、それがコンテナファイルとなる)
FROM fedora:latest
RUN dnf -y install httpd && dnf clean all
RUN echo "Welcome to Lab8010 Blog!" > /var/www/html/index.html
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
EXPOSE 80
~~~

しかしこれではよくわからないという方もいると思うので、少し解説を加えます。

~~~zsh: 上記に少し解説を加えたもの
# 作業ディレクトリ内にContainerfileがあることを確認
yasakai@yasakai-mac lab8010-web % ls -la
total 8
drwxr-xr-x  3 yasakai  staff   96  5  6 10:33 .
drwxr-xr-x  8 yasakai  staff  256  5  6 10:32 ..
-rw-r--r--  1 yasakai  staff  408  5  6 10:33 Containerfile

# Containerfileの中身を画面に出力する
yasakai@yasakai-mac lab8010-web % cat Containerfile 

# 以下の行の説明　Fedoraをベースイメージにする
FROM fedora:latest

# 以下の行の説明 dnfを使ってhttpd（Apache）をインストール
RUN dnf -y install httpd && dnf clean all

# 以下の行の説明 ウェルカムメッセージをHTMLで配置
RUN echo "Welcome to Lab8010 Blog!" > /var/www/html/index.html

# 以下の行の説明 Apacheをフォアグラウンドで実行
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]

# 以下の行の説明 Webサーバーが使うポートを公開
EXPOSE 80

yasakai@yasakai-mac lab8010-web % 

~~~

なお、このコンテナファイルを使用してコンテナを実行してみると、次のような1行だけのWebページを実行することができます。
![スクリーンショット 2025-05-08 8.35.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/05797aab-54c4-45e5-8110-ffca43ff7f95.png)

以下の行の **Welcome to Lab8010 Blog!** を変更、任意のメッセージに差し替えができます。
~~~zsh: Containerfile内の4行目
# 以下の行の説明 ウェルカムメッセージをHTMLで配置
RUN echo "Welcome to Lab8010 Blog!" > /var/www/html/index.html
~~~

しかし、このContainerfileは料理で言うなら、まだまだ開発段階のものであり商品化されていません。
実行可能なコンテナにすることは商品として売り出すようなものですから、開発段階から一歩進んだ**商品化**が必要です。そこで、商品化するためのステップに進んでいきましょう

### 発売が決まった試作品レシピを、商品化するための正式レシピおよび手順書化＝コンテナファイルを使用してコンテナイメージをBuildする

Buildは、コンテナファイルをコンテナイメージに変換するための処理です。

以下の画面出力は、Build前であるためコンテナイメージが存在しません。

~~~zsh:build前のpodman imagesの様子
# build前はコンテナイメージが存在しない
yasakai@yasakai-mac lab8010-web % podman images
REPOSITORY                   TAG         IMAGE ID      CREATED       SIZE

yasakai@yasakai-mac lab8010-web % 
~~~~

それではbuildを実行してみます。

-t オプションを使用することで、ビルドされるコンテナイメージにタグ名を指定出来ます。
このタグ名はハンバーガーチェーンの例で言えばメニューの名称のようなものです。

以下のコマンド出力は大変長いですが、podman buildを実行したことで、Containerfile内に指定された処理を順々に自動実行してくれている様子です。この工程を経て、コンテナファイルからコンテナイメージが生成されます。

ハンバーガーチェーンの例で言えば、開発中メニューが店頭で販売されるために商品化され、そのために必要な調理方法の正式なレシピが作成されているようなイメージです。

~~~zsh: コンテナファイルからコンテナイメージを作成する様子
# ユーザーが実行するのはこのコマンド
# buildの実行(末尾の.は、現在の作業ディレクトリ内のContainerfileを示す)
yasakai@yasakai-mac lab8010-web % podman build -t lab8010-web . 

#↓↓↓↓↓↓↓↓↓ここから先は上記のコマンドを受けて、自動的に実行される部分です。↓↓↓↓↓↓↓↓↓
STEP 1/5: FROM fedora:latest
Resolved "fedora" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull registry.fedoraproject.org/fedora:latest...
Getting image source signatures
Copying blob sha256:a2892c0b8e085d5cb7c85771ea06f0e14611d372b6676f0198f7a3b5e41b0b30
Copying config sha256:a30cf268d19a207fc98b29f85ae8be80b519999dc7d63c26c0aeb63caf762840
Writing manifest to image destination
STEP 2/5: RUN dnf -y install httpd && dnf clean all
Updating and loading repositories:
 Fedora 42 - aarch64 - Updates          100% | 864.9 KiB/s |   5.6 MiB |  00m07s
 Fedora 42 openh264 (From Cisco) - aarc 100% |   2.6 KiB/s |   6.0 KiB |  00m02s
 Fedora 42 - aarch64                    100% | 959.5 KiB/s |  34.2 MiB |  00m36s
Repositories loaded.
Total size of inbound packages is 20 MiB. Need to download 20 MiB.
After this operation, 76 MiB extra will be used (install 76 MiB, remove 0 B).
Package                      Arch    Version         Repository      Size
Installing:
 httpd                       aarch64 2.4.63-1.fc42   updates    156.7 KiB
Installing dependencies:
 apr                         aarch64 1.7.5-2.fc42    fedora     296.4 KiB
 apr-util                    aarch64 1.6.3-22.fc42   fedora     220.4 KiB
 apr-util-lmdb               aarch64 1.6.3-22.fc42   fedora      66.1 KiB
 dbus                        aarch64 1:1.16.0-3.fc42 fedora       0.0   B
 dbus-broker                 aarch64 36-5.fc42       fedora     421.9 KiB
 dbus-common                 noarch  1:1.16.0-3.fc42 fedora      11.2 KiB
 device-mapper               aarch64 1.02.204-3.fc42 fedora     436.7 KiB
 device-mapper-libs          aarch64 1.02.204-3.fc42 fedora     446.3 KiB
 expat                       aarch64 2.7.1-1.fc42    fedora     354.1 KiB
 fedora-logos-httpd          noarch  42.0.1-1.fc42   fedora      12.1 KiB
 fonts-filesystem            noarch  1:2.0.5-21.fc42 fedora       0.0   B
 httpd-core                  aarch64 2.4.63-1.fc42   updates      8.9 MiB
 httpd-filesystem            noarch  2.4.63-1.fc42   updates    464.0   B
 httpd-tools                 aarch64 2.4.63-1.fc42   updates    442.6 KiB
 kbd                         aarch64 2.7.1-3.fc42    fedora       2.4 MiB
 kbd-legacy                  noarch  2.7.1-3.fc42    fedora     573.6 KiB
 kbd-misc                    noarch  2.7.1-3.fc42    fedora       2.5 MiB
 kmod                        aarch64 33-3.fc42       fedora     255.2 KiB
 libcbor                     aarch64 0.11.0-3.fc42   fedora     137.9 KiB
 libfdisk                    aarch64 2.40.4-7.fc42   fedora     418.8 KiB
 libpkgconf                  aarch64 2.3.0-2.fc42    fedora     134.0 KiB
 libseccomp                  aarch64 2.5.5-2.fc41    fedora     241.4 KiB
 libusb1                     aarch64 1.0.28-2.fc42   fedora     178.7 KiB
 lmdb-libs                   aarch64 0.9.33-3.fc42   fedora     145.4 KiB
 mailcap                     noarch  2.1.54-8.fc42   fedora      86.0 KiB
 pkgconf                     aarch64 2.3.0-2.fc42    fedora     112.4 KiB
 pkgconf-m4                  noarch  2.3.0-2.fc42    fedora      14.4 KiB
 pkgconf-pkg-config          aarch64 2.3.0-2.fc42    fedora     990.0   B
 systemd                     aarch64 257.5-2.fc42    updates     14.7 MiB
 systemd-pam                 aarch64 257.5-2.fc42    updates      1.1 MiB
 systemd-shared              aarch64 257.5-2.fc42    updates      4.5 MiB
 xkeyboard-config            noarch  2.44-1.fc42     fedora       6.6 MiB
Installing weak dependencies:
 apr-util-openssl            aarch64 1.6.3-22.fc42   fedora      66.3 KiB
 cryptsetup-libs             aarch64 2.7.5-2.fc42    fedora       2.4 MiB
 diffutils                   aarch64 3.12-1.fc42     updates      1.6 MiB
 julietaula-montserrat-fonts noarch  1:9.000-2.fc42  updates      5.6 MiB
 kmod-libs                   aarch64 33-3.fc42       fedora     159.1 KiB
 libbpf                      aarch64 2:1.5.0-2.fc42  fedora     458.7 KiB
 libfido2                    aarch64 1.15.0-3.fc42   fedora     278.3 KiB
 libxkbcommon                aarch64 1.8.1-1.fc42    fedora     406.9 KiB
 mod_http2                   aarch64 2.0.29-3.fc42   fedora     455.8 KiB
 mod_lua                     aarch64 2.4.63-1.fc42   updates    133.8 KiB
 qrencode-libs               aarch64 4.1.1-10.fc42   fedora     172.8 KiB
 systemd-networkd            aarch64 257.5-2.fc42    updates      2.3 MiB
 systemd-resolved            aarch64 257.5-2.fc42    updates    708.9 KiB
 systemd-udev                aarch64 257.5-2.fc42    updates     13.8 MiB
 tpm2-tss                    aarch64 4.1.3-6.fc42    fedora       2.1 MiB

Transaction Summary:
 Installing:        48 packages

[ 1/48] httpd-filesystem-0:2.4.63-1.fc4 100% | 131.1 KiB/s |  12.2 KiB |  00m00s
[ 2/48] httpd-0:2.4.63-1.fc42.aarch64   100% | 386.1 KiB/s |  45.9 KiB |  00m00s
[ 3/48] httpd-tools-0:2.4.63-1.fc42.aar 100% | 547.5 KiB/s |  78.3 KiB |  00m00s
[ 4/48] apr-util-0:1.6.3-22.fc42.aarch6 100% | 880.1 KiB/s |  92.4 KiB |  00m00s
[ 5/48] apr-util-lmdb-0:1.6.3-22.fc42.a 100% | 469.5 KiB/s |  13.6 KiB |  00m00s
[ 6/48] mailcap-0:2.1.54-8.fc42.noarch  100% | 504.9 KiB/s |  34.3 KiB |  00m00s
[ 7/48] apr-0:1.7.5-2.fc42.aarch64      100% | 315.2 KiB/s | 119.8 KiB |  00m00s
[ 8/48] lmdb-libs-0:0.9.33-3.fc42.aarch 100% | 561.3 KiB/s |  61.7 KiB |  00m00s
[ 9/48] expat-0:2.7.1-1.fc42.aarch64    100% | 355.9 KiB/s | 112.1 KiB |  00m00s
[10/48] httpd-core-0:2.4.63-1.fc42.aarc 100% |   1.5 MiB/s |   1.4 MiB |  00m01s
[11/48] systemd-pam-0:257.5-2.fc42.aarc 100% | 650.2 KiB/s | 399.9 KiB |  00m01s
[12/48] dbus-1:1.16.0-3.fc42.aarch64    100% | 336.0 KiB/s |   7.7 KiB |  00m00s
[13/48] libfdisk-0:2.40.4-7.fc42.aarch6 100% | 154.9 KiB/s | 151.4 KiB |  00m01s
[14/48] libseccomp-0:2.5.5-2.fc41.aarch 100% | 680.5 KiB/s |  71.4 KiB |  00m00s
[15/48] dbus-broker-0:36-5.fc42.aarch64 100% | 602.0 KiB/s | 166.8 KiB |  00m00s
[16/48] dbus-common-1:1.16.0-3.fc42.noa 100% | 295.0 KiB/s |  14.5 KiB |  00m00s
[17/48] fedora-logos-httpd-0:42.0.1-1.f 100% | 546.4 KiB/s |  14.8 KiB |  00m00s
[18/48] mod_lua-0:2.4.63-1.fc42.aarch64 100% | 163.8 KiB/s |  55.7 KiB |  00m00s
[19/48] mod_http2-0:2.0.29-3.fc42.aarch 100% | 350.5 KiB/s | 157.7 KiB |  00m00s
[20/48] apr-util-openssl-0:1.6.3-22.fc4 100% | 877.3 KiB/s |  14.9 KiB |  00m00s
[21/48] libxkbcommon-0:1.8.1-1.fc42.aar 100% |   1.5 MiB/s | 152.2 KiB |  00m00s
[22/48] systemd-shared-0:257.5-2.fc42.a 100% | 592.1 KiB/s |   1.6 MiB |  00m03s
[23/48] libbpf-2:1.5.0-2.fc42.aarch64   100% | 965.8 KiB/s | 184.5 KiB |  00m00s
[24/48] kmod-libs-0:33-3.fc42.aarch64   100% | 660.3 KiB/s |  68.0 KiB |  00m00s
[25/48] cryptsetup-libs-0:2.7.5-2.fc42. 100% |   1.7 MiB/s | 525.7 KiB |  00m00s
[26/48] device-mapper-libs-0:1.02.204-3 100% |   1.2 MiB/s | 172.6 KiB |  00m00s
[27/48] xkeyboard-config-0:2.44-1.fc42. 100% | 676.2 KiB/s | 978.5 KiB |  00m01s
[28/48] device-mapper-0:1.02.204-3.fc42 100% | 175.5 KiB/s | 135.6 KiB |  00m01s
[29/48] qrencode-libs-0:4.1.1-10.fc42.a 100% | 770.2 KiB/s |  62.4 KiB |  00m00s
[30/48] diffutils-0:3.12-1.fc42.aarch64 100% | 686.2 KiB/s | 390.5 KiB |  00m01s
[31/48] systemd-resolved-0:257.5-2.fc42 100% |   1.9 MiB/s | 300.9 KiB |  00m00s
[32/48] systemd-networkd-0:257.5-2.fc42 100% |   1.2 MiB/s | 733.5 KiB |  00m01s
[33/48] fonts-filesystem-1:2.0.5-21.fc4 100% |   1.4 MiB/s |   8.6 KiB |  00m00s
[34/48] systemd-0:257.5-2.fc42.aarch64  100% | 726.4 KiB/s |   3.9 MiB |  00m05s
[35/48] kbd-0:2.7.1-3.fc42.aarch64      100% | 954.6 KiB/s | 379.0 KiB |  00m00s
[36/48] julietaula-montserrat-fonts-1:9 100% |   2.4 MiB/s |   1.6 MiB |  00m01s
[37/48] kmod-0:33-3.fc42.aarch64        100% | 873.2 KiB/s | 120.5 KiB |  00m00s
[38/48] kbd-legacy-0:2.7.1-3.fc42.noarc 100% | 270.9 KiB/s | 608.1 KiB |  00m02s
[39/48] pkgconf-pkg-config-0:2.3.0-2.fc 100% |  35.7 KiB/s |   9.9 KiB |  00m00s
[40/48] pkgconf-0:2.3.0-2.fc42.aarch64  100% |  75.8 KiB/s |  44.7 KiB |  00m01s
[41/48] pkgconf-m4-0:2.3.0-2.fc42.noarc 100% | 459.2 KiB/s |  14.2 KiB |  00m00s
[42/48] libpkgconf-0:2.3.0-2.fc42.aarch 100% | 133.1 KiB/s |  38.2 KiB |  00m00s
[43/48] systemd-udev-0:257.5-2.fc42.aar 100% | 512.4 KiB/s |   2.3 MiB |  00m05s
[44/48] libusb1-0:1.0.28-2.fc42.aarch64 100% |   1.7 MiB/s |  77.2 KiB |  00m00s
[45/48] libfido2-0:1.15.0-3.fc42.aarch6 100% |   5.2 MiB/s |  96.1 KiB |  00m00s
[46/48] libcbor-0:0.11.0-3.fc42.aarch64 100% | 924.8 KiB/s |  32.4 KiB |  00m00s
[47/48] tpm2-tss-0:4.1.3-6.fc42.aarch64 100% | 372.7 KiB/s | 398.8 KiB |  00m01s
[48/48] kbd-misc-0:2.7.1-3.fc42.noarch  100% | 317.1 KiB/s |   1.7 MiB |  00m05s
--------------------------------------------------------------------------------
[48/48] Total                           100% |   1.5 MiB/s |  19.6 MiB |  00m13s
Running transaction
[ 1/50] Verify package files            100% |   1.1 KiB/s |  48.0   B |  00m00s
[ 2/50] Prepare transaction             100% |   1.4 KiB/s |  48.0   B |  00m00s
[ 3/50] Installing apr-0:1.7.5-2.fc42.a 100% | 145.6 MiB/s | 298.2 KiB |  00m00s
[ 4/50] Installing libseccomp-0:2.5.5-2 100% | 237.6 MiB/s | 243.3 KiB |  00m00s
[ 5/50] Installing systemd-shared-0:257 100% | 505.4 MiB/s |   4.5 MiB |  00m00s
[ 6/50] Installing libfdisk-0:2.40.4-7. 100% | 409.9 MiB/s | 419.8 KiB |  00m00s
[ 7/50] Installing expat-0:2.7.1-1.fc42 100% |  34.8 MiB/s | 356.2 KiB |  00m00s
[ 8/50] Installing apr-util-0:1.6.3-22. 100% |   0.0   B/s | 221.9 KiB |  00m00s
[ 9/50] Installing httpd-tools-0:2.4.63 100% |  48.4 MiB/s | 446.3 KiB |  00m00s
[10/50] Installing libcbor-0:0.11.0-3.f 100% |   0.0   B/s | 139.3 KiB |  00m00s
[11/50] Installing libusb1-0:1.0.28-2.f 100% |   0.0   B/s | 180.3 KiB |  00m00s
[12/50] Installing libpkgconf-0:2.3.0-2 100% |   0.0   B/s | 135.1 KiB |  00m00s
[13/50] Installing pkgconf-0:2.3.0-2.fc 100% |  12.5 MiB/s | 114.9 KiB |  00m00s
[14/50] Installing pkgconf-m4-0:2.3.0-2 100% |   0.0   B/s |  14.8 KiB |  00m00s
[15/50] Installing pkgconf-pkg-config-0 100% | 197.0 KiB/s |   1.8 KiB |  00m00s
[16/50] Installing kmod-0:33-3.fc42.aar 100% |  25.4 MiB/s | 259.7 KiB |  00m00s
[17/50] Installing kbd-misc-0:2.7.1-3.f 100% | 137.5 MiB/s |   2.6 MiB |  00m00s
[18/50] Installing kbd-legacy-0:2.7.1-3 100% |  87.0 MiB/s | 623.5 KiB |  00m00s
[19/50] Installing kbd-0:2.7.1-3.fc42.a 100% | 183.6 MiB/s |   2.4 MiB |  00m00s
[20/50] Installing fonts-filesystem-1:2 100% |   0.0   B/s | 788.0   B |  00m00s
[21/50] Installing kmod-libs-0:33-3.fc4 100% |   0.0   B/s | 160.2 KiB |  00m00s
[22/50] Installing libbpf-2:1.5.0-2.fc4 100% | 448.7 MiB/s | 459.5 KiB |  00m00s
[23/50] Installing xkeyboard-config-0:2 100% | 476.5 MiB/s |   6.7 MiB |  00m00s
[24/50] Installing fedora-logos-httpd-0 100% |   3.2 MiB/s |  13.1 KiB |  00m00s
>>> Running sysusers scriptlet: dbus-common-1:1.16.0-3.fc42.noarch              
>>> Finished sysusers scriptlet: dbus-common-1:1.16.0-3.fc42.noarch             
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>> Creating group 'dbus' with GID 81.                                          
>>> Creating user 'dbus' (System Message Bus) with UID 81 and GID 81.           
>>>                                                                             
[25/50] Installing dbus-common-1:1.16.0 100% |   2.6 MiB/s |  13.6 KiB |  00m00s
[26/50] Installing dbus-broker-0:36-5.f 100% |  31.9 MiB/s | 424.4 KiB |  00m00s
[27/50] Installing dbus-1:1.16.0-3.fc42 100% |   0.0   B/s | 124.0   B |  00m00s
[28/50] Installing systemd-pam-0:257.5- 100% |  92.4 MiB/s |   1.1 MiB |  00m00s
>>> Running sysusers scriptlet: systemd-0:257.5-2.fc42.aarch64                  
>>> Finished sysusers scriptlet: systemd-0:257.5-2.fc42.aarch64                 
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>> Creating group 'systemd-journal' with GID 190.                              
>>>                                                                             
>>> Running sysusers scriptlet: systemd-0:257.5-2.fc42.aarch64                  
>>> Finished sysusers scriptlet: systemd-0:257.5-2.fc42.aarch64                 
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>> Creating group 'systemd-oom' with GID 999.                                  
>>> Creating user 'systemd-oom' (systemd Userspace OOM Killer) with UID 999 and 
>>>                                                                             
[29/50] Installing systemd-0:257.5-2.fc 100% | 161.1 MiB/s |  14.8 MiB |  00m00s
>>> Running post-install scriptlet: systemd-0:257.5-2.fc42.aarch64              
>>> Finished post-install scriptlet: systemd-0:257.5-2.fc42.aarch64             
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>>                                                                             
[30/50] Installing device-mapper-libs-0 100% | 436.8 MiB/s | 447.3 KiB |  00m00s
[31/50] Installing device-mapper-0:1.02 100% |  43.0 MiB/s | 440.3 KiB |  00m00s
[32/50] Installing cryptsetup-libs-0:2. 100% | 785.2 MiB/s |   2.4 MiB |  00m00s
[33/50] Installing lmdb-libs-0:0.9.33-3 100% |   0.0   B/s | 146.8 KiB |  00m00s
[34/50] Installing apr-util-lmdb-0:1.6. 100% |   0.0   B/s |  67.0 KiB |  00m00s
[35/50] Installing mailcap-0:2.1.54-8.f 100% |  12.1 MiB/s |  87.1 KiB |  00m00s
>>> Running sysusers scriptlet: httpd-filesystem-0:2.4.63-1.fc42.noarch         
>>> Finished sysusers scriptlet: httpd-filesystem-0:2.4.63-1.fc42.noarch        
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>> Creating group 'apache' with GID 48.                                        
>>> Creating user 'apache' (Apache) with UID 48 and GID 48.                     
>>>                                                                             
[36/50] Installing httpd-filesystem-0:2 100% |   2.1 MiB/s |   2.2 KiB |  00m00s
[37/50] Installing httpd-core-0:2.4.63- 100% | 250.2 MiB/s |   9.0 MiB |  00m00s
[38/50] Installing httpd-0:2.4.63-1.fc4 100% |  31.3 MiB/s | 160.4 KiB |  00m00s
[39/50] Installing mod_lua-0:2.4.63-1.f 100% |   0.0   B/s | 134.5 KiB |  00m00s
[40/50] Installing mod_http2-0:2.0.29-3 100% |  49.7 MiB/s | 458.1 KiB |  00m00s
>>> Running sysusers scriptlet: systemd-udev-0:257.5-2.fc42.aarch64             
>>> Finished sysusers scriptlet: systemd-udev-0:257.5-2.fc42.aarch64            
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>> Creating group 'systemd-coredump' with GID 998.                             
>>> Creating user 'systemd-coredump' (systemd Core Dumper) with UID 998 and GID 
>>>                                                                             
>>> Running sysusers scriptlet: systemd-udev-0:257.5-2.fc42.aarch64             
>>> Finished sysusers scriptlet: systemd-udev-0:257.5-2.fc42.aarch64            
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>> Creating group 'systemd-timesync' with GID 997.                             
>>> Creating user 'systemd-timesync' (systemd Time Synchronization) with UID 997
>>>                                                                             
[41/50] Installing systemd-udev-0:257.5 100% |  60.0 MiB/s |  13.9 MiB |  00m00s
>>> Running post-install scriptlet: systemd-udev-0:257.5-2.fc42.aarch64         
>>> Finished post-install scriptlet: systemd-udev-0:257.5-2.fc42.aarch64        
>>> Scriptlet output:                                                           
>>> Failed to preset unit: Unit system-systemdx2dcryptsetup.slice does not exist
>>>                                                                             
>>> Running sysusers scriptlet: systemd-networkd-0:257.5-2.fc42.aarch64         
>>> Finished sysusers scriptlet: systemd-networkd-0:257.5-2.fc42.aarch64        
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>> Creating group 'systemd-network' with GID 192.                              
>>> Creating user 'systemd-network' (systemd Network Management) with UID 192 an
>>>                                                                             
[42/50] Installing systemd-networkd-0:2 100% |  92.0 MiB/s |   2.3 MiB |  00m00s
>>> Running post-install scriptlet: systemd-networkd-0:257.5-2.fc42.aarch64     
>>> Finished post-install scriptlet: systemd-networkd-0:257.5-2.fc42.aarch64    
>>> Scriptlet output:                                                           
>>> Created symlink '/etc/systemd/system/sysinit.target.wants/systemd-network-ge
>>>                                                                             
>>> Running sysusers scriptlet: systemd-resolved-0:257.5-2.fc42.aarch64         
>>> Finished sysusers scriptlet: systemd-resolved-0:257.5-2.fc42.aarch64        
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>> Creating group 'systemd-resolve' with GID 193.                              
>>> Creating user 'systemd-resolve' (systemd Resolver) with UID 193 and GID 193.
>>>                                                                             
[43/50] Installing systemd-resolved-0:2 100% |  41.0 MiB/s | 712.9 KiB |  00m00s
>>> Running post-install scriptlet: systemd-resolved-0:257.5-2.fc42.aarch64     
>>> Finished post-install scriptlet: systemd-resolved-0:257.5-2.fc42.aarch64    
>>> Scriptlet output:                                                           
>>> Created symlink '/etc/systemd/system/dbus-org.freedesktop.resolve1.service' 
>>> Created symlink '/etc/systemd/system/sysinit.target.wants/systemd-resolved.s
>>>                                                                             
[44/50] Installing libxkbcommon-0:1.8.1 100% | 399.1 MiB/s | 408.7 KiB |  00m00s
[45/50] Installing julietaula-montserra 100% | 347.7 MiB/s |   5.6 MiB |  00m00s
>>> Running sysusers scriptlet: tpm2-tss-0:4.1.3-6.fc42.aarch64                 
>>> Finished sysusers scriptlet: tpm2-tss-0:4.1.3-6.fc42.aarch64                
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>> Creating group 'tss' with GID 59.                                           
>>> Creating user 'tss' (Account used for TPM access) with UID 59 and GID 59.   
>>>                                                                             
[46/50] Installing tpm2-tss-0:4.1.3-6.f 100% | 431.8 MiB/s |   2.2 MiB |  00m00s
[47/50] Installing libfido2-0:1.15.0-3. 100% | 273.3 MiB/s | 279.8 KiB |  00m00s
[48/50] Installing apr-util-openssl-0:1 100% |   0.0   B/s |  67.2 KiB |  00m00s
[49/50] Installing qrencode-libs-0:4.1. 100% |   0.0   B/s | 174.7 KiB |  00m00s
[50/50] Installing diffutils-0:3.12-1.f 100% |   7.0 MiB/s |   1.6 MiB |  00m00s
>>> Running trigger-install scriptlet: systemd-0:257.5-2.fc42.aarch64           
>>> Finished trigger-install scriptlet: systemd-0:257.5-2.fc42.aarch64          
>>> Scriptlet output:                                                           
>>> Failed to connect to audit log, ignoring: Invalid argument                  
>>>                                                                             
Complete!
Removed 20 files, 11 directories (total of 75 MiB). 0 errors occurred.
--> db5e4e8e7813
STEP 3/5: RUN echo "Welcome to Lab8010 Blog!" > /var/www/html/index.html
--> a0c922f7c61e
STEP 4/5: CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
--> 09b682b8e2a0
STEP 5/5: EXPOSE 80
COMMIT lab8010-web
--> b977ca2b3500
Successfully tagged localhost/lab8010-web:latest
b977ca2b35001a5a3b30caae670eebc7b13b3b60d833dee3daa0b0d62c4cf571

# ↑↑↑↑↑↑↑↑↑ここまでが自動的に実行された内容↑↑↑↑↑↑↑↑↑
yasakai@yasakai-mac lab8010-web % 
~~~

非常に長い実行の様子なので、**特にエンジニア経験がない方からすると"とてつもなく長い作業をしているな..."と思うかもしれません**が、上記の出力の9割が自動的に実行されている処理です。

Buildが終わった後に、再度podman imagesを実行した際の様子です。
2つのコンテナイメージが表示されています。

作成したコンテナイメージは1つ(local/lab8010-web)ですが、このコンテナイメージとしてFedoraを使用したためFedoraのイメージも自動的にダウンロードされています。

~~~zsh:build後のpodman imagesの様子
yasakai@yasakai-mac lab8010-web % podman images
REPOSITORY                         TAG         IMAGE ID      CREATED        SIZE
localhost/lab8010-web              latest      b977ca2b3500  5 minutes ago  270 MB
registry.fedoraproject.org/fedora  latest      a30cf268d19a  19 hours ago   176 MB
yasakai@yasakai-mac lab8010-web % 

##1つ目のコンテナイメージはpodman buildで作成されたもの
##2つ目のコンテナイメージはpodman buildで使用されたベースイメージのFedoraイメージ
~~~

ここで、**『どうして1つのコンテナイメージのビルドにも関わらず、最終的に2つのコンテナイメージが準備されたのだろう？』** と疑問を持った方もいるでしょう。

これを語る場合、コンテナイメージの仕組み上重要な考え方となる**レイヤー**について解説をします。

### 料理に含まれる具材＝レイヤー

唐突に、某有名ハンバーガーチェーンから2つのメニューを掲示してみました。
私自身だったり子供もおもちゃ付きのセットが好きなのでよくお世話になっています。

さて、この2つのメニューを見比べてみるとどのような違いがあるでしょうか？

https://www.mcdonalds.co.jp/products/1010/

https://www.mcdonalds.co.jp/products/1020/

おそらくほとんどの方は、**チーズがあるかないかの違い**ということに気がつくでしょう。

逆の見方をすれば、どちらの商品にも**ハンバーガーは共通した要素**であるとも言えます。
もう少し踏み込んでみれば、**ハンバーガーの作り方はあらゆるバーガーの基礎**とも言えるでしょう。

挟むものを増やしてみたり。

https://www.mcdonalds.co.jp/products/4500/

挟むものを変えてみたり。

https://www.mcdonalds.co.jp/products/1070/

今回私がBuildしたコンテナイメージは、**Fedoraを使用して、その中でhttpdを実行し、更に特定の静的コンテンツをhttpdで公開する**ようにしたものです。
これを構成するためには、まず**Fedoraだけのコンテナイメージ**を取得する必要があるわけです。
言い換えれば、**チーズバーガーを作るためには、まずハンバーガーのレシピを覚える必要がある。ハンバーガーを作る途中で1枚のチーズを入れればチーズバーガーが作れる**という具合です。

つまり、ここでは**チーズ＝レイヤー**と言えます。

では実際にコンテナイメージをレイヤー構造に分解してみましょう。

~~~zsh: コンテナイメージのレイヤー構造を確かめる

# 2つのコンテナイメージを確認する
yasakai@yasakai-mac lab8010-web % podman images
REPOSITORY                         TAG         IMAGE ID      CREATED       SIZE
localhost/lab8010-web              latest      b977ca2b3500  5 hours ago   270 MB
registry.fedoraproject.org/fedora  latest      a30cf268d19a  24 hours ago  176 MB

# fedoraのイメージは1つのレイヤーのみを持ちます。サイズは176MBです。
yasakai@yasakai-mac lab8010-web % podman history fedora:latest 
ID            CREATED       CREATED BY    SIZE        COMMENT
a30cf268d19a  24 hours ago  KIWI 10.2.19  176MB       
yasakai@yasakai-mac lab8010-web % 

# httpdとコンテンツを含めた私がビルドしたイメージには合計で5つのレイヤーがあります。
# dnfコマンドのレイヤーは93.6MBで、echoコマンドのレイヤーは4.1kBであることがわかります。
yasakai@yasakai-mac lab8010-web % podman history localhost/lab8010-web:latest 
ID            CREATED       CREATED BY                                     SIZE        COMMENT
a0c922f7c61e  5 hours ago   /bin/sh -c #(nop) EXPOSE 80                    0B          FROM 09b682b8e2a0
<missing>     5 hours ago   /bin/sh -c #(nop) CMD ["/usr/sbin/httpd", ...  0B          FROM a0c922f7c61e
<missing>     5 hours ago   /bin/sh -c echo "Welcome to Lab8010 Blog!"...  4.1kB       FROM db5e4e8e7813
db5e4e8e7813  5 hours ago   /bin/sh -c dnf -y install httpd && dnf cle...  93.6MB      FROM registry.fedoraproject.org/fedora:latest
a30cf268d19a  24 hours ago  KIWI 10.2.19                                   176MB       
yasakai@yasakai-mac lab8010-web % 
~~~

上のコマンド出力を手短に説明するとこうなります。
- イメージ名　registry.fedoraproject.org/fedoraはレイヤーを1つだけ持っており、レイヤーのIDはa30cf268d19aである。そのサイズは176MBである。ベーシックなハンバーガーのような存在。
- イメージ名　localhost/lab8010-webはレイヤーを5つ持っており、レイヤーサイズの合計は270MBである。
    - このイメージには、1つ目のイメージのfedoraも含まれている
    - 理由はfedoraをベースイメージとして、httpdのパッケージを追加しているため
    - ベーシックなバーガーに、追加のトッピングとしてレイヤーを追加しているようなケース


書きながら思ったのですが、**レイヤーのサイズというのは食材のカロリーみたい**ですね(笑)
実際に、コンテナの世界において**コンテナのイメージサイズをいかに小さくするか**というのは運用管理上重要なポイントの1つです。読み込むデータの量がそれだけ数ないことは、コンテナのロード時間短縮やストレージスペースの節約など、多岐にわたる利点を産むからです。

ではどうやればコンテナイメージのサイズを小さくできるかというと、コンテナファイルの記述内容次第です。
同じ処理をするにしても、効率の良い書き方をすることで容量の違いが生まれます。
※この記事では、コンテナの基本を紹介することを目的としているため、コンテナファイルの効率的な記述には触れません。

#### ベースイメージはどこにあるのか？
さて、上記の例では私はコンテナのベースイメージとしてFedoraを使用しました。
ベースイメージとは、Fedoraだけでなく、CentOSやUbuntuなどさまざまなものが選べます。
ハンバーガーなどで言えば、ベースイメージというとパンに近いかもしれませんね。

~~サンドイッチショップ SUBWAYですと、パンが選べますね。これもベースイメージを選んでいる感覚に近い気がします。~~

https://www.subway.co.jp/menu/howtoorder/step02.html

Red Hatも、コンテナのベースイメージとして利用可能なRed Hat Enterprise Linuxを用意しています。
コンテナ用に用意されたイメージをUBI(Universal Base Image)という名称として提供しており、その詳細については以下のサイトから確認が可能です。

https://www.redhat.com/ja/blog/introducing-red-hat-universal-base-image

これらのベースイメージは**レジストリ**と呼ばれる保管庫がありますので、次はレジストリについて見ていきます。

### レシピを集中管理している本社の商品開発部門＝レジストリ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/5c52f4ae-0f45-42c7-921a-87f60d613e0c.png" width="300">

飲食チェーンでは、本社の商品開発部門が各メニューのレシピを一元管理しています。  
この「秘伝のレシピ」は企業の競争力の源でもあり、外部に漏れることは許されません。

例えば、類似のビジネスをしているケンタッキーフライドチキン（KFC）のスパイスは、世界で3人しか知らないと言われています。

>ハーブとスパイスの配合を知っているのは、世界でたったの３人。スパイスは複数の工場で数種類ずつ配合され、店舗に向けて出荷されます。各店舗でそれらをブレンドして初めて、11種類のハーブ＆スパイスが完成。カーネルが生み出した秘伝の味は、こうして守られているのです。
https://www.kfc.co.jp/about_kfc/commitment/secretrecipe

<img src="https://images.ctfassets.net/jax7ylg56usf/7CGhG1O9Iq60vN0mm5QY07/4cfad4ff9085a81729c8dd79c4fcb8df/recipe_heading01.png" width="400"><img src="https://images.ctfassets.net/jax7ylg56usf/3Dfl8xeHNy0RqhEZWUGJdc/4d1f17d5b77639190d961bec43744f59/recipe_heading02.png" width="400">
<img src="https://images.ctfassets.net/jax7ylg56usf/49A5SHs5FgBN6wYZWo90EV/0ce723a9cc04944c298891763801cabd/recipe_heading03.png" width="400">

このように、「レシピ＝ノウハウ」の管理は、現実世界においても極めて重要な経営戦略です。そして、コンテナの世界にも、これとよく似た考え方が存在します。

コンテナイメージも、企業にとって重要な知的財産である秘伝のレシピと同様に、その詳細をみだりに公開することは推奨されません。なぜなら、コンテナはアプリケーションを実行する環境そのものであり、商用アプリケーションの内部構造や実行プロセスが外部に知られてしまうと、セキュリティ上の脆弱性を突かれるリスクが高まるためです。

そこで、秘伝のレシピを厳重に保護するように、**組織内でコンテナイメージを安全に管理するための仕組みとしてプライベートレジストリ**が用意されます。プライベートレジストリを導入することで、自社独自の環境に最適化されたイメージの管理や、コンプライアンス要件への対応などが可能になります。

プライベートレジストリ構成する場合にはいくつかのソリューションが存在します。
※一部のリンクは当該ソリューションの使い方を示していたり、またはレジストリ以外の用途も持っている場合があります。

https://goharbor.io/

https://www.docker.com/blog/how-to-use-your-own-registry-2/

https://rheb.hatenablog.com/entry/202002-quay

https://www.redhat.com/en/technologies/cloud-computing/quay

https://gitlab-docs.creationline.com/ee/user/packages/container_registry/

https://jfrog.com/artifactory/

一方、公開しても問題のないコンテナイメージは、パブリックレジストリを通じて広く共有・配布されます。

Docker Hub：最も普及しているパブリックレジストリであり、多くの公式イメージが公開されています。

https://hub.docker.com/

Quay.io：Red Hat関連のイメージを中心に利用されており、高い信頼性が特徴のレジストリサービスです。

https://quay.io/

このパブリックレジストリの存在は、料理の世界におけるクックパッドのようなレシピ共有サイトに例えることができます。世界中のレシピを手軽に検索し、利用できるのと同じように、公開されたコンテナイメージを容易に入手し、活用することができる点が共通しているためです。

https://cookpad.com/jp

最後に、このレジストリの中にあるイメージをどのように使用するかについて説明をしておきます。
例えば、CentOS (またはCentOS Stream)の公式イメージを使用したい場合は、次のコマンドを実行するだけでQuay.io(Red Hatが運営するパブリックコンテナレジストリ)から取得ができます。
~~~zsh: コンテナイメージのpullと取得されたイメージの表示
# podman環境で、quay.ioからcentosの最新イメージを入手するコマンド(タグをつけない場合は最新のものが自動ダウンロードされる)
podman pull quay.io/centos/centos

# docker環境で、quay.ioからcentosの最新イメージを入手するコマンド(タグをつけない場合は最新のものが自動ダウンロードされる)
docker pull quay.io/centos/centos

# podman環境で、quay.ioからCentOS Stream 10のイメージを入手するコマンド
podman pull quay.io/centos/centos:stream10

# podman環境で、quay.ioからCentOS 8.3.2011のイメージを入手するコマンド
podman pull quay.io/centos/centos:centos8.3.2011

# podman pullなどでイメージをpull(ダウンロード)した結果の様子
yasakai@yasakai-mac ~ % podman images
REPOSITORY                         TAG             IMAGE ID      CREATED       SIZE
localhost/lab8010-web              latest          b977ca2b3500  11 hours ago  270 MB
registry.fedoraproject.org/fedora  latest          a30cf268d19a  30 hours ago  176 MB
quay.io/centos/centos              stream10        b9bba37ca0bf  6 days ago    335 MB
quay.io/centos/centos              centos8.3.2011  300e315adb2f  4 years ago   217 MB
yasakai@yasakai-mac ~ % 
~~~
https://quay.io/repository/centos/centos?tab=info
※製品提供形式の変更に伴いCentOSとCentOS Streamのイメージが両方とも同じレポジトリ内に保管されています。
※どのバージョン、どの製品を指定するかは、タグ名を付帯することで指定が可能です。

また、コンテナイメージに採用したいイメージをコンテナファイル内に記述する場合は次のように記述します。
~~~zsh: コンテナファイルの記述例
これらのFROMから始まる行は、通常コンテナファイルの1行目に記述し、ベースとなるOSを指定する。

# 最新のFedoraコンテナイメージを、fedoraprojectのレジストリから取得する
FROM: registry.fedoraproject.org/fedora:latest

# CentOS Stream10のコンテナイメージを、quay.ioのレジストリから取得する
FROM: quay.io/centos/centos:stream10

# CentOS 8.3.2011のコンテナイメージを、quay.ioのレジストリから取得する
FROM: quay.io/centos/centos:centos8.3.2011

# 最新のUbuntuのイメージを取得します。このように、レジストリの名前指定がない場合はコンテナエンジンにデフォルトで設定されたレジストリに対してイメージを探しに行きます。
FROM Ubuntu

# 補足: 応用的なテクニックとして、1つのコンテナファイルに2つのFROMを指定する場合があります。
# これはマルチステージビルドと呼ばれる方法で、ビルドされるコンテナイメージのサイズを小さくするなどいくつかの利点のために行われます。
~~~

### 商品化されたハンバーガーのレシピ＝Buildされた後の成果物であるコンテナイメージ
チェーン展開をしている店舗である以上、商品の作り方は決まったレシピに基づく必要があります。
![thumbnail_hamburger_buns.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/024357ab-8c35-40d1-a4f3-db4e3bbe8a60.jpeg)![thumbnail_hamburger_meat.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/e9c21b44-34d2-4da7-82a3-15f5346121fa.jpeg)![thumbnail_hamburger_vegetable.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/1f125f81-7422-4898-a1b8-10fee6f2f8fa.jpeg)

- バンズは2枚
- ビーフパティーは1枚
- ピクルスは1枚
- ケチャップとマスタードを規定量

コンテナの世界では、**イミュータブル(不変的)** という特性があり、コンテナは常にコンテナイメージから展開されるといつも同じ状態で実行されます。
**感覚や勘、目分量**に頼って作られる料理もありますが、チェーン店ではそれは許されません。

### レシピを使用して実際に調理を行う＝コンテナイメージに対するRunの実行
作成済みのコンテナイメージを **run** コマンドで実行する行為は、料理における「実際に調理を始めること」に相当します。
具材（＝必要なプログラムや設定など）はすでに用意されていて、それを調理器具を使って調理し、盛り付けて出すところまでが **run** の役割です。

実際にrunを実行したのがこちらです。

~~~zsh:podman runを実行した様子
## lab8010-webという名前のイメージを使い、コンテナをバックグラウンド起動し、コンテナの通信ポート80をホストOSの8080にマッピングする指定をした様子
yasakai@yasakai-mac lab8010-web % podman run -d -p 8080:80 lab8010-web

## コンテナランタイムが生成され、一意の識別子が発行された様子
76534b6633840dd98814eb0d37c8b583a3c2eeff554f60f58f18d54f83841060

## 
yasakai@yasakai-mac lab8010-web % podman ps
CONTAINER ID  IMAGE                         COMMAND               CREATED        STATUS        PORTS                 NAMES
76534b663384  localhost/lab8010-web:latest  /usr/sbin/httpd -...  5 seconds ago  Up 6 seconds  0.0.0.0:8080->80/tcp  stupefied_shirley
yasakai@yasakai-mac lab8010-web % curl http://localhost:8080
Welcome to Lab8010 Blog!
yasakai@yasakai-mac lab8010-web % 
~~~

https://quay.io/repository/centos/centos?tab=info
※製品提供形式の変更に伴いCentOSとCentOS Streamのイメージが両方とも同じレポジトリ内に保管されています。
※どのバージョン、どの製品を指定するかは、タグ名を付帯することで指定が可能です。

また、コンテナイメージに採用したいイメージをコンテナファイル内に記述する場合は次のように記述します。
~~~zsh: コンテナファイルの記述例
これらのFROMから始まる行は、通常コンテナファイルの1行目に記述し、ベースとなるOSを指定する。

# 最新のFedoraコンテナイメージを、fedoraprojectのレジストリから取得する
FROM: registry.fedoraproject.org/fedora:latest

# CentOS Stream10のコンテナイメージを、quay.ioのレジストリから取得する
FROM: quay.io/centos/centos:stream10

# CentOS 8.3.2011のコンテナイメージを、quay.ioのレジストリから取得する
FROM: quay.io/centos/centos:centos8.3.2011

# 最新のUbuntuのイメージを取得します。このように、レジストリの名前指定がない場合はコンテナエンジンにデフォルトで設定されたレジストリに対してイメージを探しに行きます。
FROM Ubuntu

# 補足: 応用的なテクニックとして、1つのコンテナファイルに2つのFROMを指定する場合があります。
# これはマルチステージビルドと呼ばれる方法で、ビルドされるコンテナイメージのサイズを小さくするなどいくつかの利点のために行われます。

~~~

https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/9/html/using_image_mode_for_rhel_to_build_deploy_and_manage_operating_systems/building-derived-bootable-images-by-using-multi-stage-builds_building-and-testing-the-rhel-bootable-container-images#building-derived-bootable-images-by-using-multi-stage-builds_building-and-testing-the-rhel-bootable-container-images

このように、レジストリから組織やアプリケーション開発者は、コンテナのベースとなるイメージを選び、それをもとにアプリケーションの実行環境となるコンテナを構築していきます。

特にベースイメージに関して言えば、podman pullで素のままのCentOS StreamやFedora、RHELなどを取得、起動することで大変軽量なOS環境として動かすこともできます。いきなりContainerfileに対して諸々のコマンド実行やファイルのコピーなどを書いてみる以外にも、まずはOSとして動かしてみてからContainerfileに記述予定の作業が本当に適用できるかを試すこともできます。

### 完成したハンバーガー＝コンテナインスタンス
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/fc53e2ee-11d8-4782-8e46-e25369e6a11c.png" width="300">

**レシピ通りに作られたハンバーガー＝コンテナイメージから生まれたコンテナインスタンス**です。
時に文脈の中で、**『コンテナを動かす』** とか **『コンテナを作る』** と言われた場合に概ねこのコンテナインスタンスを示していることが多いでしょう。

一般的にコンテナとは、メモリ上で起動し、アプリケーションなどのワークロードを実行する独立した単位を指します。

料理においてもレシピ（設計図）に基づいて調理することで、実際に「食べられる」状態になった料理が出来上がります。

実際のハンバーガーチェーンでは複数のメニューがあり、各メニューに対応するレシピが存在します。
このレシピは、全国の各チェーン店に配布される必要があります。なぜならすべての店舗で各メニューは同じ分量で作られる必要があるからです。

実際のハンバーガーチェーンでは、本社の製品開発部から各店舗に対してレシピの情報が伝達されることによって、各店舗では新メニューが作れるようになります。

既に上の項目で触れた**レジストリ**がまさにレシピを保管する商品開発部門のように、コンテナイメージを保管してくれる存在というわけです。

### 結局コンテナとは何なのか？
記事の最後に記述する内容としては、若干タイミングが微妙な気もしますが、あえて記述してみます。

皆さんはハンバーガーのようなファストフードをどんな時に食べますか？

個人差はあると言ってしまうと身も蓋もありませんが、、おそらく殆どの場合が**急いでいて時間がない場合**で、逆に言えば**フォーマルな食事会などでファストフードが振る舞われることは(特別な会を除いては)ない**でしょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/f6f6469a-e45c-4cd8-8349-dc81945e1da6.png" width="300">

ファストフードという名前にもある通り、**素早さ/手軽さ**はコンテナの特性の1つです。

コンテナはよく仮想マシンと比較をされることがあります。
仮想マシンはコンテナと比べてCPUもメモリもディスクなどのリソース消費が大きいため、軽食ではなく定食料理のようなものかもしれません。(食事の量で例えた場合)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680306/febcd705-09b2-49ff-ad64-17e615d70a44.png" width="300">

- 定食はファストフードよりも準備に時間がかかる (仮想マシンは起動時間が長い)
- 定食はファストフードよりも含まれる食品が多い　(仮想マシンはコンテナよりもリソース消費が大きい)
- 定食はファストフードよりも片付けに時間がかかる (仮想マシンは停止が遅い、コンテナは停止も削除も高速)

もちろんこの3つの要素だけで、2つの異なるワークロードの違いを語り尽くせているとは言えないでしょう。
また、定食がファストフードに優っている点はいくつもありますが...今回はコンテナが主役の記事ということと記事の締めの段階ということもあるため、ひとまずこれ以上は掘り下げないこととします。

## あとがき
私は10年以上ハイパーバイザー環境で実装する仮想化基盤に関わってきたエンジニアですが、2024年の転職を機にKubernetesプラットフォームと関わることになりました。このため、コンテナについての経験はそれと比べれば決して長いわけではなく、比較的新人のような位置付けだと自らを定義しています。

この記事は、これから学習する皆様に向けたものとしつつも、自分自身にとっても見返すことを想定したメモのような位置付けにもあります。そのため、自分にとってわかりやすいと感じるレベルまでしか掘り下げていない項目もあるかもしれません。ですので表現がわかりにくかったり、追記してほしいなと感じるところがあればぜひお知らせください。追って記事を訂正/加筆を行っていく予定です。

## 付録 - お役立ちリンク

https://podman.io/

https://www.docker.com/

https://containerd.io/

https://cri-o.io/

https://podman-desktop.io/

https://docs.docker.com/desktop/

https://www.redhat.com/ja/blog/introducing-red-hat-universal-base-image

https://goharbor.io/

https://www.docker.com/blog/how-to-use-your-own-registry-2/

https://rheb.hatenablog.com/entry/202002-quay

https://www.redhat.com/en/technologies/cloud-computing/quay

https://gitlab-docs.creationline.com/ee/user/packages/container_registry/

https://jfrog.com/artifactory/

https://hub.docker.com/

https://quay.io/