Podmanの学習記録#2

# 関連記事

- [Podmanの学習記録#1](https://qiita.com/v1tam1n/items/d779878f4adde53f02f0) 
- [Podmanの学習記録#2](https://qiita.com/v1tam1n/items/d2d7ba0a5b78654cf6a4) <-- 今回はこれ

# はじめに

[Podmanの学習記録#1](https://qiita.com/v1tam1n/items/d779878f4adde53f02f0)の続きです。

主に以下のような内容を行います。


- イメージ管理の方法
- Containerfileによるカスタムイメージの作成
- ボリュームマウントの方法
- コンテナのトラブルシューティングの基本


# イメージの管理

## イメージの検索

```shell
test@ubuntu-podman:~$ podman search hello-world
INDEX       NAME                                                DESCRIPTION                                      STARS       OFFICIAL    AUTOMATED
docker.io   docker.io/library/hello-world                       Hello World! (an example of minimal Dockeriz...  2097        [OK]        
docker.io   docker.io/rancher/hello-world                                                                        4                       
docker.io   docker.io/okteto/hello-world                                                                         0                       
docker.io   docker.io/golift/hello-world                        Hello World Go-App built by Go Lift Applicat...  0                       
docker.io   docker.io/tacc/hello-world                                                                           0                       
docker.io   docker.io/armswdev/c-hello-world                    Simple hello-world C program on Alpine Linux...  0                       
docker.io   docker.io/tutum/hello-world                         Image to test docker deployments. Has Apache...  90                      [OK]
docker.io   docker.io/thomaspoignant/hello-world-rest-json      This project is a REST hello-world API to bu...  2                       
docker.io   docker.io/kitematic/hello-world-nginx               A light-weight nginx container that demonstr...  152                     
docker.io   docker.io/dockercloud/hello-world                   Hello World!                                     20                      [OK]
docker.io   docker.io/ansibleplaybookbundle/hello-world-apb     An APB which deploys a sample Hello World! a...  1                       [OK]
docker.io   docker.io/ansibleplaybookbundle/hello-world-db-apb  An APB which deploys a sample Hello World! a...  2                       [OK]
docker.io   docker.io/crccheck/hello-world                      Hello World web server in under 2.5 MB           17                      [OK]
docker.io   docker.io/strimzi/hello-world-consumer                                                               0                       
docker.io   docker.io/strimzi/hello-world-producer                                                               0                       
docker.io   docker.io/businessgeeks00/hello-world-nodejs                                                         0                       
docker.io   docker.io/koudaiii/hello-world                                                                       0                       
docker.io   docker.io/freddiedevops/hello-world-spring-boot                                                      0                       
docker.io   docker.io/strimzi/hello-world-streams                                                                0                       
docker.io   docker.io/garystafford/hello-world                  Simple hello-world Spring Boot service for t...  0                       [OK]
docker.io   docker.io/ppc64le/hello-world                       Hello World! (an example of minimal Dockeriz...  2                       
docker.io   docker.io/tsepotesting123/hello-world                                                                0                       
docker.io   docker.io/kevindockercompany/hello-world                                                             0                       
docker.io   docker.io/dandando/hello-world-dotnet                                                                0                       
docker.io   docker.io/vad1mo/hello-world-rest                   A simple REST Service that echoes back all t...  7                       [OK]
test@ubuntu-podman:~$ 
```
## イメージのプル

```shell
test@ubuntu-podman:~$ podman pull hello-world:latest
Resolved "hello-world" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
Trying to pull docker.io/library/hello-world:latest...
Getting image source signatures
Copying blob 719385e32844 done  
Copying config 9c7a54a9a4 done  
Writing manifest to image destination
Storing signatures
9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d
test@ubuntu-podman:~$ 
```

## イメージの詳細

```shell
test@ubuntu-podman:~$ podman image inspect hello-world:latest
[
    {
        "Id": "9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d",
        "Digest": "sha256:4f53e2564790c8e7856ec08e384732aa38dc43c52f02952483e3f003afbf23db",
        "RepoTags": [
            "docker.io/library/hello-world:latest",
            "localhost/hello-world:latest"
        ],
        "RepoDigests": [
            "docker.io/library/hello-world@sha256:4f53e2564790c8e7856ec08e384732aa38dc43c52f02952483e3f003afbf23db",
            "docker.io/library/hello-world@sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3",
            "localhost/hello-world@sha256:4f53e2564790c8e7856ec08e384732aa38dc43c52f02952483e3f003afbf23db",
            "localhost/hello-world@sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2023-05-04T17:37:03.872958712Z",
        "Config": {
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/hello"
            ]
        },
        "Version": "20.10.23",
        "Author": "",
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 19929,
        "VirtualSize": 19929,
        "GraphDriver": {
            "Name": "overlay",
            "Data": {
                "UpperDir": "/home/test/.local/share/containers/storage/overlay/01bb4fce3eb1b56b05adf99504dafd31907a5aadac736e36b27595c8b92f07f1/diff",
                "WorkDir": "/home/test/.local/share/containers/storage/overlay/01bb4fce3eb1b56b05adf99504dafd31907a5aadac736e36b27595c8b92f07f1/work"
            }
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:01bb4fce3eb1b56b05adf99504dafd31907a5aadac736e36b27595c8b92f07f1"
            ]
        },
        "Labels": null,
        "Annotations": {},
        "ManifestType": "application/vnd.docker.distribution.manifest.v2+json",
        "User": "",
        "History": [
            {
                "created": "2023-05-04T17:37:03.801840823Z",
                "created_by": "/bin/sh -c #(nop) COPY file:201f8f1849e89d53be9f6aa76937f5e209d745abfd15a8552fcf2ba45ab267f9 in / "
            },
            {
                "created": "2023-05-04T17:37:03.872958712Z",
                "created_by": "/bin/sh -c #(nop)  CMD [\"/hello\"]",
                "empty_layer": true
            }
        ],
        "NamesHistory": [
            "localhost/hello-world:latest",
            "docker.io/library/hello-world:latest"
        ]
    }
]
test@ubuntu-podman:~$ 
```

## イメージのtagづけ

```shell
test@ubuntu-podman:~$ podman tag hello-world:latest localhost/hello-world:latest
test@ubuntu-podman:~$ podman images | grep hello
docker.io/library/hello-world  latest      9c7a54a9a43c  4 months ago  19.9 kB
localhost/hello-world          latest      9c7a54a9a43c  4 months ago  19.9 kB
test@ubuntu-podman:~$
```

## イメージの削除

```shell
test@ubuntu-podman:~$ podman rmi hello-world:latest
Untagged: docker.io/library/hello-world:latest
test@ubuntu-podman:~$ podman rmi localhost/hello-world:latest
Untagged: localhost/hello-world:latest
Deleted: 9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d
test@ubuntu-podman:~$ 
```

他のイメージから参照されていないイメージは以下で削除できる。

```shell
podman image prune
```

# Containerfileによるカスタムイメージの作成

## イメージのビルド

```Dockerfile:Containerfile
# ベースイメージ
FROM python:3.11

# ラベル情報
LABEL jp.co.example.environment="dev"
LABEL jp.co.example.version="0.0.1"

# 環境変数
ENV HTTP_PORT=8000

# ポートバインド
EXPOSE $HTTP_PORT

# 作業ディレクトリを指定
WORKDIR /opt/fastapi/src

# ホストからファイルをコピー
COPY app.py .

# Pythonモジュールインストール
RUN pip install fastapi uvicorn[standard]

# Entrypoint（コンテナ起動時に必ず実行するコマンド）
ENTRYPOINT ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
```

```python:app.py
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}
```

`fastapi-sample-app`というイメージ名でtag名を`test`としてイメージをビルドする。

```shell
podman build -t fastapi-sample-app .
```

イメージを確認する。

```shell
test@ubuntu-podman:~/work$ podman images
REPOSITORY                    TAG         IMAGE ID      CREATED         SIZE
localhost/fastapi-sample-app  latest      4340cdc505db  56 seconds ago  1.1 GB
docker.io/library/nginx       latest      f5a6b296b8a2  2 weeks ago     191 MB
docker.io/library/python      3.11        b94d01b49295  4 weeks ago     1.03 GB
test@ubuntu-podman:~/work$ 
```

## FastAPIをコンテナで起動する

```shell
podman run -d --rm --name fastapi-app \
-p 8000:8000 \
localhost/fastapi-sample-app:latest
```

起動したコンテナのデフォルトのディレクトリを確認すると、`Containerfile`で指定した`WORKDIR`になっていることが分かる。

```shell
test@ubuntu-podman:~/work$ podman exec fastapi-app pwd
/opt/fastapi/src
test@ubuntu-podman:~/work$ 
```

アクセス確認。`{"message":"Hello World"}`が表示されたらOK。

```shell
test@ubuntu-podman:~/work$ curl localhost:8000
{"message":"Hello World"}
test@ubuntu-podman:~/work$ 
```

コンテナをストップ。（`--rm` オプションを付けているのでストップと同時にコンテナも削除される。）

```shell
test@ubuntu-podman:~/work$ podman stop fastapi-app
fastapi-app
test@ubuntu-podman:~/work$ 
```

# ボリュームマウント

コンテナ内で作成されたファイルなどは、コンテナの削除と同時に消えてしまう。しかし、データベースに登録したデータなどがコンテナのダウンの度に消えるのは嬉しくない。

そこで、コンテナではデータを永続化するための仕組みが用意されている。ホストのディレクトリやファイルをコンテナ内にマウントすることで、永続化を実現する。

## コンテナボリュームを作成する方法

以下のコマンドでコンテナボリュームを作成できる。

```shell
test@ubuntu-podman:~$ podman volume create hello
hello
test@ubuntu-podman:~$ 
```

ボリュームの詳細情報を確認する。

```shell
test@ubuntu-podman:~/work$ podman volume inspect hello
[
    {
        "Name": "hello",
        "Driver": "local",
        "Mountpoint": "/home/test/.local/share/containers/storage/volumes/hello/_data",
        "CreatedAt": "2023-09-26T02:19:16.972967692Z",
        "Labels": {},
        "Scope": "local",
        "Options": {}
    }
]
test@ubuntu-podman:~/work$ 
```

ボリュームマウントは`-v`オプションで指定する。

```shell
test@ubuntu-podman:~$ podman run -d --name nginx-vol-test -v hello:/world nginx ls -al /world
b99234876a3a214fd8dd985eb71f7350f2c2d8cb6f6ab0bcf62ad051c881a40a
test@ubuntu-podman:~$ podman logs nginx-vol-test
total 8
drwxr-xr-x 2 root root 4096 Sep 26 02:19 .
dr-xr-xr-x 1 root root 4096 Sep 26 02:28 ..
test@ubuntu-podman:~$ podman rm -af
b99234876a3a214fd8dd985eb71f7350f2c2d8cb6f6ab0bcf62ad051c881a40a
test@ubuntu-podman:~$ 
```

`hello`ボリュームにファイルをインポートしてみる。

```shell
test@ubuntu-podman:~$ echo "Hello World" > test.txt
test@ubuntu-podman:~$ tar zcvf test.tar.gz test.txt
test.txt
test@ubuntu-podman:~$ podman volume import hello test.tar.gz
```

再度ボリュームマウントして、`test.txt`がコンテナ内にもあることを確認する。

```shell
test@ubuntu-podman:~$ podman run -d --name nginx-vol-test -v hello:/world nginx ls -al /world
f846c661c57e2c03987fc53cdca505a308bdd5ca1b05c4f5a9356deec5cbed07
test@ubuntu-podman:~$ podman logs nginx-vol-test
total 12
drwxr-xr-x 2 root root 4096 Sep 26 02:31 .
dr-xr-xr-x 1 root root 4096 Sep 26 02:34 ..
-rw-rw-r-- 1 1000 1000   12 Sep 26 02:30 test.txt
test@ubuntu-podman:~$ podman rm -af
f846c661c57e2c03987fc53cdca505a308bdd5ca1b05c4f5a9356deec5cbed07
test@ubuntu-podman:~$ 
```

最後にボリュームを削除する。

```shell
test@ubuntu-podman:~$ podman volume rm hello
hello
test@ubuntu-podman:~$ 
```

## ディレクトリのマウント

テスト用のディレクトリとファイルを作成する。

```
mkdir html
echo "Hello World" > html/index.html
```

`-v`オプションで以下のように指定することで、ホストのディレクトリをコンテナにマウントできる。

```shell
podman run -d --rm --name nginx-vol-test \
-p 8080:80 \
-v `pwd`/html:/usr/share/nginx/html \
nginx
```

アクセス確認をすると、作成した `inde.html` が反映されている。

```
test@ubuntu-podman:~$ curl localhost:8080
Hello World
test@ubuntu-podman:~$ podman rm -af
061c6513a0cff2a4a88f336f778ea374f6d99692769fc5a0da4238d42fa22ba5
test@ubuntu-podman:~$ 
```

# コンテナのトラブルシューティングの基本

コンテナ構築時に上手く起動できないときに確認すべき基本的なポイントを紹介する。

個人的によく遭遇するのは以下のような事象。

- ボリュームマント時のパーミッションの問題（`podman unshare`）
- ポートマッピングの不整合（コンテ内で利用してるポート番号が確認するなど）
- すでにホストで同じポートが利用されている場合

コンテナのログを確認するには以下を実行する。まずはログを確認するのが基本でしょう。

```shell
podman logs <コンテナ名>
```

# まとめ

今回は以下を学びました。

- イメージ管理の方法
- Containerfileによるカスタムイメージの作成
- ボリュームマウントの方法
- コンテナのトラブルシューティングの基本