Podman Containerのエクスポート/インポートをやってみた

# はじめに
現在所属しているプロジェクトではインターネットへ接続できない閉域環境を利用しているためインストール時にインターネット通信が必要なアプリケーションをそのままインストールすることができない。そこで、インターネットへ接続可能な環境でコンテナを構築して、閉域環境へファイルコピーして転送する方法を実施した

# 環境情報
- OS: Windows 10 Pro 22H2
- RAM: 8.0GB
- SSD: 256GB
- Podman Desktop: v1.1.0
- Podman: v4.5.1

## コンテナのエクスポート
今回はbitnami redmineのコンテナをエクスポート/インポートする
まずはコンテナが稼働しているマシンにてエクスポートを行う

(1)Windows PowerShell(管理者)にてWSLでpodman-machine-defaultを実行する
```
PS C:\WINDOWS\system32> wsl -d podman-machine-default
```

(2)コンテナの一覧を確認する。今回は`user_mariadb_1`と`user_redmine_1`をエクスポート対象とする
```
[user@hostname1 ~]$ podman ps
CONTAINER ID  IMAGE                           COMMAND               CREATED       STATUS      PORTS                   NAMES
19fabb453774  docker.io/bitnami/mariadb:10.6  /opt/bitnami/scri...  3 months ago  Up 13 days                          user_mariadb_1
906c42d0abb1  docker.io/bitnami/redmine:4     /opt/bitnami/scri...  3 months ago  Up 13 days  0.0.0.0:8181->3000/tcp  user_redmine_1
```

(3)コンテナをエクスポートする。まず`podman commit コンテナ名 イメージ名`でイメージとして登録し、`podman save -o ファイル名.tar イメージ名`でイメージとしてエクスポートする
```
[user@hostname1 ~]$ podman commit user_mariadb_1 redmine_20231009/mariadb:10.6
[user@hostname1 ~]$ podman commit user_redmine_1 redmine_20231009/redmine:4

[user@hostname1 ~]$  podman image list
REPOSITORY                 TAG         IMAGE ID      CREATED        SIZE
localhost/redmine_20231009/redmine  4           7b01673e5cdb  14 minutes ago  1.24 GB
localhost/redmine_20231009/mariadb  10.6        27d427b36822  15 minutes ago  341 MB
docker.io/bitnami/mariadb           10.6        50d16d13ae3d  3 months ago    341 MB
docker.io/library/busybox           latest      b539af69bc01  4 months ago    5.1 MB
docker.io/bitnami/redmine           4           ae7219167241  17 months ago   637 MB

[user@hostname1 ~]$ podman save -o my_mariadb.tar redmine_20231009/mariadb:10.6
[user@hostname1 ~]$ podman save -o my_redmine.tar redmine_20231009/redmine:4
```

(4)ボリュームの一覧を確認する。今回の環境では永続データの保存先としてボリュームを利用している。コンテナのエクスポートとは別にボリュームをエクスポートする必要がある
```
[user@hostname1 ~]$ podman volume list
DRIVER      VOLUME NAME
local       user_mariadb_data
local       user_redmine_data
```

(5)ボリュームをエクスポートする。コマンドは`podman volume export ボリューム名 ファイル名.tar`
```
[user@hostname1 ~]$ podman volume export user_mariadb_data --output user_mariadb_data.tar
[user@hostname1 ~]$ podman volume export user_redmine_data --output user_redmine_data.tar
```

(6)エクスポートした4つのファイルと合わせてコンテナ起動用に`docker-compose.yml`もインポート先マシンに移動する
今回の`docker-compose.yml`は以下となっている
```
version: '2'
services:
  mariadb:
    image: docker.io/bitnami/mariadb:10.6
    volumes:
      - 'mariadb_data:/bitnami/mariadb'
    environment:
      # ALLOW_EMPTY_PASSWORD is recommended only for development.
      - ALLOW_EMPTY_PASSWORD=yes
      - MARIADB_USER=bn_redmine
      - MARIADB_DATABASE=bitnami_redmine
  redmine:
    image: docker.io/bitnami/redmine:4
    ports:
      - '8181:3000'
    volumes:
      - 'redmine_data:/bitnami/redmine'
    depends_on:
      - mariadb
    environment:
      # ALLOW_EMPTY_PASSWORD is recommended only for development.
      - ALLOW_EMPTY_PASSWORD=yes
      - REDMINE_DATABASE_HOST=mariadb
      - REDMINE_DATABASE_PORT_NUMBER=3306
      - REDMINE_DATABASE_USER=bn_redmine
      - REDMINE_DATABASE_NAME=bitnami_redmine
volumes:
  mariadb_data:
    driver: local
  redmine_data:
    driver: local
```

## コンテナのインポート
コンテナの移行先マシンにてインポート作業を行う

(1)エクスポートしたイメージをインポートする。コマンドは`podman load -i ファイル名.tar`
```
[user@hostname2 ~]$ podman load -i my_mariadb.tar
[user@hostname2 ~]$ podman load -i my_redmine.tar
```

イメージとして登録されたことを確認する
```
[user@hostname2 ~]$ podman image list
REPOSITORY                          TAG         IMAGE ID      CREATED         SIZE
localhost/redmine_20231009/redmine  4           7b01673e5cdb  31 minutes ago  1.24 GB
localhost/redmine_20231009/mariadb  10.6        27d427b36822  32 minutes ago  341 MB
```

(2)`docker-compose.yml`を編集する。インポートしたイメージをベースにコンテナを起動するように以下を書き換える
```
version: '2'
services:
  mariadb:
    image: localhost/redmine_20231009/mariadb:10.6 <- docker.io/bitnami/mariadb:10.6
---<snip>---
  redmine:
    image: localhost/redmine_20231009/redmine:4 <- docker.io/bitnami/redmine:5
---<snip>---
```

(3)コンテナを起動する。この段階ではエラーで終了する
```
[user@hostname2 ~]$ podman-compose up -f docker-compose.yml -d
```

(4)エクスポートしたボリュームをインポートする。前述の`podman-compose`コマンドの実行によって空のボリュームが作成されるのでインポートコマンドでデータをインポートする。podman-composeコマンドを実行したときのディレクトリ名がボリュームの接頭辞として最初に付与される。今回は`bitnammi-redmine`フォルダ内で作業した。インポートコマンドは`podman volume import ボリューム名 ファイル名.tar
```
[user@hostname2 ~]$ podman volume list
DRIVER      VOLUME NAME
local       bitnami-redmine_mariadb_data
local       bitnami-redmine_redmine_data

[user@hostname2 ~]$ podman volume import bitnami-redmine_mariadb_data user_mariadb_data.tar
[user@hostname2 ~]$ podman volume import bitnami-redmine_redmine_data user_redmine_data.tar
```

(5)再度コンテナを起動する
```
[user@hostname2 ~]$ podman-compose up -f docker-compose.yml -d
```

(6)しばらく経過した後でdocker-compose.ymlで指定したRedmineサービスのポート番号(http://localhost:8181) へブラウザでアクセスする。移行前環境で利用していたユーザにてログインができ、インストールしていたプラグインもそのまま利用可能となっていることが確認できる
![20231009_redmine_screenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3472468/85860b53-6792-3703-1477-3a364f267021.jpeg)

# おわりに
今回の検証によりコンテナのエクスポート/インポート手順を確認することができた。
今回のようにdocker-composeにて複数コンテナを連携するような環境では、コンテナを直接エクスポート/インポートするのではなく以下のような手順となる。
(1)移行元マシンでカスタマイズしたコンテナを`podman commit`コマンドにてイメージとしてローカルレジストリに登録する
(2)移行元マシンでローカルレジストリに登録したイメージを`podman save`コマンドにてtarファイルとしてエクスポートする
(3)永続データ保存先としてvolumeを利用している場合は、`podman volume export`コマンドにてtarファイルとしてエクスポートする
(4)移行元マシンで利用しているdocker-compose.ymlファイルも移行先にコピーする
(5)移行先マシンにて`podman load`コマンドでエクスポートしたイメージをインポートする
(6)移行先マシンにて`docker-commpose.yml`を編集して、インポートしたイメージを利用してコンテナを起動するように書き換える
(7)移行先マシンで一度`podman-compose up`コマンドにてコンテナ/ボリュームを作成し、作成されたボリュームに対して`podman volume import`コマンドにてデータをインポートする
(8)移行先マシンにてvolumeへのデータインポート完了後に再度`podman-compose up`コマンドにてコンテナを起動する

本手順を活用することでインターネット接続が可能な環境でコンテナをカスタマイズし、閉域環境へ移行する手法を取ることで閉域環境でもコンテナアプリケーションを活用することができる

# 参考ページ
- [Dockerのシステム移行手順（バックアップおよび復元方法）](https://qiita.com/mikoski01/items/7d71ef7d167a6b78219a)
- [podman-volume-export](https://docs.podman.io/en/latest/markdown/podman-volume-export.1.html)