Podman podsを使用したConfluent Platformの導入

## はじめに

背景として、RHEL(Red Hat Enterprise Linux)にConfluent Platformを導入することになり、経緯は省きますが、Confluentから公開されている[Dockerコンテナイメージ](https://hub.docker.com/u/confluentinc)を使用して導入作業を行いました。コンポーネント(ZooKeeper、Kafka、Kafka Connect、Schema Registry、ksqlDB、Control Center)ごとにコンテナを起動するので、運用やモビリティ面を考慮して、Docker Compose、もしくは、Podman podsで複数コンテナをまとめて管理できるようにしたいです。ここでは、導入先であるRHEL8のDockerのサポート廃止とPodmanの採用などの理由により、Podman podsを使用することにしました。

この記事では備忘録も兼ねて、Podman podsを使用したConfluent Platformの導入ログを記載しています。Confluent Platformは使わないけどPodman podsを使いたいという方にも参考になる部分はあるかと思います。

## 参考情報

- [Moving from docker-compose to Podman pods](https://www.redhat.com/sysadmin/compose-podman-pods)
- [Podmanのポッドとコンテナ作成手順の覚書](https://denor.jp/podman%E3%81%AE%E3%83%9D%E3%83%83%E3%83%89%E3%81%A8%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E4%BD%9C%E6%88%90%E6%89%8B%E9%A0%86%E3%81%AE%E8%A6%9A%E6%9B%B8#Podman)

## 環境情報

- Red Hat Enterprise Linux release 8.5 (Ootpa)
- Confluent Platform 7.0.1

## 導入ログ

### 事前作業

#### Portの使用状況の確認

一応、各コンポーネントで利用予定のPortが使用可能か確認しておきます。

- 例) ZooKeeperのデフォルトPort:2181の確認
```
$ curl http://localhost:2181
curl: (7) Failed to connect to localhost port 2181: Connection refused
```

#### 外部ボリューム(ホスト上のZooKeeperとKafkaのデータ保持のためのディレクトリ)の作成

初めは外部ボリュームなしで導入したのですが、作業を諸々進めた後にコンポーネントのパラメーターをどうしても変更しないといけなくなった際、PodmanではPod作成後のマニュアルでの変更はできないようでPodの再作成が必要になりました。この時、外部ボリュームがマウントされていないとこれまでデータが全て失われます。なので、検証用であれ外部ボリュームはマウントしておくのが無難かと思います。作成方法については、[こちら](https://docs.confluent.io/ja-jp/platform/6.2.0/installation/docker/operations/external-volumes.html)を参照してください。この記事の下部にも[参考](#参考-外部ボリュームのマウント)としては記載しています。

### 導入作業

Podman podsの手順は以下のようになっています。

- `podman pod create`で空のPodを作成
- `podman run`でコンテナを先に作成したPod内で起動
- `podman generate kube`でPodの構成をYAMLファイルに出力
    - YAMLファイルに出力しておくと、次回からPodとしてすぐに起動できますし、別環境への導入にも流用できます。
- `podman play kube`でYAMLファイルを指定してPodの実行ができます。
    - YAMLファイルに慣れている方は、`podman run`などを使わずに、初めからYAMLファイルを作成してPodを実行した方が早いかもしれません。

#### `podman pod create`で空のPodを作成

- Pod: confluentを作成
    - **コンテナで使用予定のPortはここで全て指定しないといけません。**
```bash
$ sudo podman pod create --name confluent -p 2181:2181/tcp,9092:9092/tcp,8081:8081/tcp,8088:8088/tcp,9021:9021/tcp,8083:8083/tcp,10091:10091/tcp
```

#### `podman run`で各コンポーネントのコンテナをPod内で起動

コンテナには、Confluentから公開されている[Dockerコンテナイメージ](https://hub.docker.com/u/confluentinc)を使用しており、Kafka Connectのみコンテナ起動時にJDBC Source/Sink ConnectorとElasticsearch Sink Connectorのインストールコマンドを含めるために別途作成しました。

各コンポーネントのパラメーターを環境変数として動的に指定することができますので、必要なパラメーターを指定してください。パラメーターについては、[こちら](https://docs.confluent.io/platform/current/installation/docker/config-reference.html#docker-configuration-parameters)を参照してください。

##### ZooKeeper

```bash
$ sudo podman run -d --pod=confluent -e ZOOKEEPER_CLIENT_PORT="2181" -e KAFKA_OPTS="-Dlog4j.configuration=file:/etc/kafka/log4j.properties" --name=ice-zookeeper docker.io/confluentinc/cp-zookeeper:7.0.1
```

##### Kafka

```bash
$ sudo podman run -d --pod confluent -e KAFKA_ZOOKEEPER_CONNECT="localhost:2181" -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP="PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT" -e KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://localhost:9092,EXTERNAL://xx.xx.xx.xx:10091" -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR="1" -e KAFKA_CONFLUENT_LICENSE_TOPIC_REPLICATION_FACTOR="1" -e KAFKA_CONFLUENT_BALANCER_TOPIC_REPLICATION_FACTOR="1" -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR="1" -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR="1" -e CONFLUENT_METRICS_REPORTER_TOPIC_REPLICAS="1" -e KAFKA_OPTS="-Dlog4j.configuration=file:/etc/kafka/log4j.properties" --name ice-broker docker.io/confluentinc/cp-server:7.0.1
```

##### Kafka Connect

```bash
$ sudo podman run -d --name ice-kafka-connect --pod confluent -e CONNECT_BOOTSTRAP_SERVERS="localhost:9092" -e CONNECT_LISTENERS="http://0.0.0.0:8083" -e CONNECT_GROUP_ID="ice-connect-cluster" -e CONNECT_CONFIG_STORAGE_TOPIC="connect-configs" -e CONNECT_OFFSET_STORAGE_TOPIC="connect-offsets" -e CONNECT_STATUS_STORAGE_TOPIC="connect-statuses" -e CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR="1" -e CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR="1" -e CONNECT_STATUS_STORAGE_REPLICATION_FACTOR="1" -e CONNECT_KEY_CONVERTER="io.confluent.connect.avro.AvroConverter" -e CONNECT_VALUE_CONVERTER="io.confluent.connect.avro.AvroConverter" -e CONNECT_KEY_CONVERTER_SCHEMA_REGISTRY_URL="http://localhost:8081" -e CONNECT_VALUE_CONVERTER_SCHEMA_REGISTRY_URL="http://localhost:8081" -e CONNECT_INTERNAL_KEY_CONVERTER="io.confluent.connect.avro.AvroConverter" -e CONNECT_INTERNAL_VALUE_CONVERTER="io.confluent.connect.avro.AvroConverter" -e CONNECT_REST_ADVERTISED_HOST_NAME="connect" -e CONNECT_PLUGIN_PATH="/usr/share/confluent-hub-components" -e KAFKA_OPTS="-Dlog4j.configuration=file:/etc/kafka/connect-log4j.properties" --name ice-kafka-connect docker.io/xxxxxxxxx/cp-connector-jdbc-elasticsearch:latest
```

- (参考)今回作成したDockerfile(docker.io/xxxxxxxxx/cp-connector-jdbc-elasticsearch:latest)
```dockerfile
FROM docker.io/confluentinc/cp-server-connect:7.0.1
RUN confluent-hub install --no-prompt confluentinc/kafka-connect-jdbc:10.3.3 \
  && confluent-hub install --no-prompt confluentinc/kafka-connect-elasticsearch:11.1.8
```

##### Schame Registry

```bash
$ sudo podman run -d --pod confluent -e SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS="PLAINTEXT://localhost:9092" -e SCHEMA_REGISTRY_LISTENERS="http://0.0.0.0:8081" -e SCHEMA_REGISTRY_HOST_NAME="schema-registry" -e KAFKA_OPTS="-Dlog4j.configuration=file:/etc/schema-registry/log4j.properties" --name ice-schema-registry docker.io/confluentinc/cp-schema-registry:7.0.1
```

##### ksqlDB

```bash
$ sudo podman run -d --name ice-ksqldb-server --pod confluent -e KSQL_BOOTSTRAP_SERVERS="localhost:9092" -e KSQL_HOST_NAME="ksqldb-server" -e KSQL_LISTENERS="http://0.0.0.0:8088" -e KSQL_KSQL_SCHEMA_REGISTRY_URL="http://localhost:8081" -e KSQL_KSQL_CONNECT_URL="http://localhost:8083" -e KAFKA_OPTS="-Dlog4j.configuration=file:/etc/ksqldb-server/log4j.properties" docker.io/confluentinc/cp-ksqldb-server:7.0.1
```

##### Control Center

```bash
$ sudo podman run -d --name ice-control-center --pod confluent -e CONTROL_CENTER_BOOTSTRAP_SERVERS="localhost:9092" -e CONTROL_CENTER_REPLICATION_FACTOR="1" -e CONTROL_CENTER_CONNECT_CONNECT1_CLUSTER="http://localhost:8083" -e CONTROL_CENTER_KSQL_KSQLDB1_URL="http://localhost:8088" -e CONTROL_CENTER_SCHEMA_REGISTRY_URL="http://localhost:8081" -e KAFKA_OPTS="-Dlog4j.configuration=file:/etc/confluent-control-center/log4j.properties" docker.io/confluentinc/cp-enterprise-control-center:7.0.1
```

コンテナの稼働状況(`podman ps`)やログ(`podman logs <containerID/container名>`)を確認し、特に問題なければ導入作業は完了です。

YAMLファイルを出力してみる。

#### `podman generate kube`でPodの構成をYAMLファイルに出力

- Pod: confluentのYAMLファイルを出力
```
$ sudo podman generate kube confluent > ice-confluent.yaml
```

```yaml:ice-confluent.yaml
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-3.4.2
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2022-03-07T13:18:53Z"
  labels:
    app: confluent
  name: confluent
spec:
  containers:
  - image: docker.io/confluentinc/cp-zookeeper:7.0.1
    name: confluent-ice-zookeeper
    ports:
    - containerPort: 2181
      hostPort: 2181
    - containerPort: 9092
      hostPort: 9092
    - containerPort: 10091
      hostPort: 10091
    - containerPort: 8083
      hostPort: 8083
    - containerPort: 8081
      hostPort: 8081
    - containerPort: 8088
      hostPort: 8088
    - containerPort: 9021
      hostPort: 9021
    resources: {}
    securityContext:
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_AUDIT_WRITE
    volumeMounts:
    - mountPath: /etc/zookeeper/secrets
      name: edab71c22fdaed4a4df998340874e1a44c813378c7e761336578206298cfa7b2-pvc
    - mountPath: /var/lib/zookeeper/data
      name: eba9189ae8e18ed4746b735e86c794c950ee4c732ecc361f8e9f78571a6091cb-pvc
    - mountPath: /var/lib/zookeeper/log
      name: 074de8171cd8e478c8b2248552333cd1e5d01d66bd8caa49e58c69ac4451962f-pvc
  - image: docker.io/confluentinc/cp-server:7.0.1
    name: confluent-ice-broker
    resources: {}
    securityContext:
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_AUDIT_WRITE
    volumeMounts:
    - mountPath: /etc/kafka/secrets
      name: c80e733ce6255244040cd1829d68fec6a7c23485624e881b797ee26f82689ee0-pvc
    - mountPath: /var/lib/kafka/data
      name: eed423b5242e3d5bb35117493c8933ff2db7096ec45fc53f9f88024207aefbe1-pvc
  - image: docker.io/xxxxxxxxx/cp-connector-jdbc-elasticsearch:latest
    name: confluent-ice-kafka-connect
    resources: {}
    securityContext:
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_AUDIT_WRITE
    volumeMounts:
    - mountPath: /etc/kafka/secrets
      name: 279968e5e8d44904508a460433e6017f3680c9ddcff096341900f7da536eda2b-pvc
    - mountPath: /var/lib/kafka/data
      name: 67a7342ed0e77fd58a6c85433bff8656ea91c4c94edbbb250c66b4a4d8a29bd2-pvc
    - mountPath: /etc/kafka-connect/jars
      name: 649e2e7e7a7b30b7955e1c210daef2776e6c226520855108eddf470326578f53-pvc
    - mountPath: /etc/kafka-connect/secrets
      name: eba230fb252f453fdaf383c27b260eb5026c32b5d31883a9bc11996c15b89bc8-pvc
  - image: docker.io/confluentinc/cp-schema-registry:7.0.1
    name: confluent-ice-schema-registry
    resources: {}
    securityContext:
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_AUDIT_WRITE
    volumeMounts:
    - mountPath: /etc/schema-registry/secrets
      name: 0364489a7dbd67de77b1cbbae2f0a33d135a7d28168c5d04eb47fce3cdac1daa-pvc
  - image: docker.io/confluentinc/cp-ksqldb-server:7.0.1
    name: confluent-ice-ksqldb-server
    resources: {}
    securityContext:
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_AUDIT_WRITE
  - image: docker.io/confluentinc/cp-enterprise-control-center:7.0.1
    name: confluent-ice-control-center
    resources: {}
    securityContext:
      capabilities:
        drop:
        - CAP_MKNOD
        - CAP_AUDIT_WRITE
  restartPolicy: Always
  volumes:
  - name: eed423b5242e3d5bb35117493c8933ff2db7096ec45fc53f9f88024207aefbe1-pvc
    persistentVolumeClaim:
      claimName: eed423b5242e3d5bb35117493c8933ff2db7096ec45fc53f9f88024207aefbe1
  - name: 649e2e7e7a7b30b7955e1c210daef2776e6c226520855108eddf470326578f53-pvc
    persistentVolumeClaim:
      claimName: 649e2e7e7a7b30b7955e1c210daef2776e6c226520855108eddf470326578f53
  - name: eba230fb252f453fdaf383c27b260eb5026c32b5d31883a9bc11996c15b89bc8-pvc
    persistentVolumeClaim:
      claimName: eba230fb252f453fdaf383c27b260eb5026c32b5d31883a9bc11996c15b89bc8
  - name: edab71c22fdaed4a4df998340874e1a44c813378c7e761336578206298cfa7b2-pvc
    persistentVolumeClaim:
      claimName: edab71c22fdaed4a4df998340874e1a44c813378c7e761336578206298cfa7b2
  - name: eba9189ae8e18ed4746b735e86c794c950ee4c732ecc361f8e9f78571a6091cb-pvc
    persistentVolumeClaim:
      claimName: eba9189ae8e18ed4746b735e86c794c950ee4c732ecc361f8e9f78571a6091cb
  - name: 074de8171cd8e478c8b2248552333cd1e5d01d66bd8caa49e58c69ac4451962f-pvc
    persistentVolumeClaim:
      claimName: 074de8171cd8e478c8b2248552333cd1e5d01d66bd8caa49e58c69ac4451962f
  - name: c80e733ce6255244040cd1829d68fec6a7c23485624e881b797ee26f82689ee0-pvc
    persistentVolumeClaim:
      claimName: c80e733ce6255244040cd1829d68fec6a7c23485624e881b797ee26f82689ee0
  - name: 279968e5e8d44904508a460433e6017f3680c9ddcff096341900f7da536eda2b-pvc
    persistentVolumeClaim:
      claimName: 279968e5e8d44904508a460433e6017f3680c9ddcff096341900f7da536eda2b
  - name: 67a7342ed0e77fd58a6c85433bff8656ea91c4c94edbbb250c66b4a4d8a29bd2-pvc
    persistentVolumeClaim:
      claimName: 67a7342ed0e77fd58a6c85433bff8656ea91c4c94edbbb250c66b4a4d8a29bd2
  - name: 0364489a7dbd67de77b1cbbae2f0a33d135a7d28168c5d04eb47fce3cdac1daa-pvc
    persistentVolumeClaim:
      claimName: 0364489a7dbd67de77b1cbbae2f0a33d135a7d28168c5d04eb47fce3cdac1daa
status: {}
```

参考情報([Moving from docker-compose to Podman pods](https://www.redhat.com/sysadmin/compose-podman-pods)、[Podmanのポッドとコンテナ作成手順の覚書](https://denor.jp/podman%E3%81%AE%E3%83%9D%E3%83%83%E3%83%89%E3%81%A8%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E4%BD%9C%E6%88%90%E6%89%8B%E9%A0%86%E3%81%AE%E8%A6%9A%E6%9B%B8#Podman))のようなYAMLファイルにはならず、指定した環境変数などがYAMLファイル上から確認できない。

原因分からず。。。直接手を加えることにしました。

- YAMLファイルを修正(環境変数の追加など)
```yaml:ice-confluent-fix.yaml
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-3.4.2
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2022-03-03T07:50:29Z"
  labels:
    app: confluent
  name: confluent
spec:
  containers:
  - image: docker.io/confluentinc/cp-zookeeper:7.0.1
    name: ice-zookeeper
    ports:
    - containerPort: 2181
      hostPort: 2181
    env:
    - name: ZOOKEEPER_CLIENT_PORT
      value: 2181
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/kafka/log4j.properties
    volumes:
    - 
  - image: docker.io/confluentinc/cp-server:7.0.1
    name: ice-broker
    ports:
    - containerPort: 9092
      hostPort: 9092
    - containerPort: 10091
      hostPort: 10091
    env:
    - name: KAFKA_ZOOKEEPER_CONNECT
      value: localhost:2181
    - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
      value: PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT
    - name: KAFKA_ADVERTISED_LISTENERS
      value: PLAINTEXT://localhost:9092,EXTERNAL://xx.xx.xx.xx:10091
    - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
      value: 1
    - name: KAFKA_CONFLUENT_LICENSE_TOPIC_REPLICATION_FACTOR
      value: 1
    - name: KAFKA_CONFLUENT_BALANCER_TOPIC_REPLICATION_FACTOR
      value: 1
    - name: KAFKA_TRANSACTION_STATE_LOG_MIN_ISR
      value: 1
    - name: KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR
      value: 1
    - name: CONFLUENT_METRICS_REPORTER_TOPIC_REPLICAS
      value: 1
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/kafka/log4j.properties
    volumes:
    - 
  - image: docker.io/xxxxxxxxx/cp-connector-jdbc-elasticsearch:latest
    name: ice-kafka-connect
    ports:
    - containerPort: 8083
      hostPort: 8083
    env:
    - name: CONNECT_BOOTSTRAP_SERVERS
      value: localhost:9092
    - name: CONNECT_LISTENERS
      value: http://0.0.0.0:8083
    - name: CONNECT_GROUP_ID
      value: ice-connect-cluster
    - name: CONNECT_CONFIG_STORAGE_TOPIC
      value: connect-configs
    - name: CONNECT_OFFSET_STORAGE_TOPIC
      value: connect-offsets
    - name: CONNECT_STATUS_STORAGE_TOPIC
      value: connect-statuses
    - name: CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR
      value: 1
    - name: CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR
      value: 1
    - name: CONNECT_STATUS_STORAGE_REPLICATION_FACTOR
      value: 1
    - name: CONNECT_KEY_CONVERTER
      value: io.confluent.connect.avro.AvroConverter
    - name: CONNECT_VALUE_CONVERTER
      value: io.confluent.connect.avro.AvroConverter
    - name: CONNECT_KEY_CONVERTER_SCHEMA_REGISTRY_URL
      value: http://localhost:8081
    - name: CONNECT_VALUE_CONVERTER_SCHEMA_REGISTRY_URL
      value: http://localhost:8081
    - name: CONNECT_INTERNAL_KEY_CONVERTER
      value: io.confluent.connect.avro.AvroConverter
    - name: CONNECT_INTERNAL_VALUE_CONVERTER
      value: io.confluent.connect.avro.AvroConverter
    - name: CONNECT_REST_ADVERTISED_HOST_NAME
      value: connect
    - name: CONNECT_PLUGIN_PATH
      value: /usr/share/confluent-hub-components
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/kafka/connect-log4j.properties 
  - image: docker.io/confluentinc/cp-schema-registry:7.0.1
    name: ice-schema-registry
    ports:
    - containerPort: 8081
      hostPort: 8081
    env:
    - name: SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS
      value: localhost:9092
    - name: SCHEMA_REGISTRY_LISTENERS
      value: http://0.0.0.0:8081
    - name: SCHEMA_REGISTRY_HOST_NAME
      value: schema-registry
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/schema-registry/log4j.properties
  - image: docker.io/confluentinc/cp-ksqldb-server:7.0.1
    name: ice-ksqldb-server
    ports:
    - containerPort: 8088
      hostPort: 8088
    env:
    - name: KSQL_BOOTSTRAP_SERVERS
      value: localhost:9092
    - name: KSQL_HOST_NAME
      value: ksqldb-server
    - name: KSQL_LISTENERS
      value: http://0.0.0.0:8088
    - name: KSQL_KSQL_SCHEMA_REGISTRY_URL
      value: http://localhost:8081
    - name: KSQL_KSQL_CONNECT_URL
      value: http://localhost:8083
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/ksqldb-server/log4j.properties
  - image: docker.io/confluentinc/cp-enterprise-control-center:7.0.1
    name: ice-control-center
    ports:
    - containerPort: 9021
      hostPort: 9021
    env:
    - name: CONTROL_CENTER_BOOTSTRAP_SERVERS
      value: localhost:9092
    - name: CONTROL_CENTER_REPLICATION_FACTOR
      value: 1
    - name: CONTROL_CENTER_CONNECT_CONNECT1_CLUSTER
      value: http://localhost:8083
    - name: CONTROL_CENTER_KSQL_KSQLDB1_URL
      value: http://localhost:8088
    - name: CONTROL_CENTER_SCHEMA_REGISTRY_URL
      value: http://localhost:8081
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/confluent-control-center/log4j.properties
```

#### `podman play kube`でYAMLファイルからPodの実行

- 現在のPodを削除して、YAMLファイルから再作成
```
$ sudo podman play kube ice-confluent-fix.yaml
```

コンテナの稼働状況(`podman ps`)やログ(`podman logs <containerID/container名>`)を確認し、特に問題なければOK

#### (参考) 外部ボリュームのマウント

手順は、[こちら](https://docs.confluent.io/ja-jp/platform/6.2.0/installation/docker/operations/external-volumes.html)を参考にしました。手順上はコンテナ起動時に外部ボリュームを指定しているが、今回はすでにYAMLファイルまで作成しているので、YAMLファイルに追加する形にしました。

- ホスト上にディレクトリの作成
```
# mkdir -p vol1/zk-data
# mkdir -p vol2/zk-txn-logs
# mkdir -p vol3/kafka-data
```

- コンテナの実行ユーザーから読み書きできるようにpermission(検証用なので777で)を変更
```
# chmod -R 777 vol1/zk-data
# chmod -R 777 vol2/zk-txn-logs
# chmod -R 777 vol3/kafka-data
```

- YAMLファイルの変更

YAMLファイルに`.spec.containers.volumeMounts`(Zookeeper、Kafka)と`.spec.volumes`を追加しました。

```yaml:ice-confluent-add-pv.yaml
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-3.4.2
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2022-03-03T07:50:29Z"
  labels:
    app: confluent
  name: confluent
spec:
  containers:
  - image: docker.io/confluentinc/cp-zookeeper:7.0.1
    name: ice-zookeeper
    ports:
    - containerPort: 2181
      hostPort: 2181
    env:
    - name: ZOOKEEPER_CLIENT_PORT
      value: 2181
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/kafka/log4j.properties
    # 追加
    volumeMounts: 
    - mountPath: /var/lib/zookeeper/data
      name: zk-data
    - mountPath: /var/lib/zookeeper/log
      name: zk-txn-logs
  - image: docker.io/confluentinc/cp-server:7.0.1
    name: ice-broker
    ports:
    - containerPort: 9092
      hostPort: 9092
    - containerPort: 10091
      hostPort: 10091
    env:
    - name: KAFKA_ZOOKEEPER_CONNECT
      value: localhost:2181
    - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
      value: PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT
    - name: KAFKA_ADVERTISED_LISTENERS
      value: PLAINTEXT://localhost:9092,EXTERNAL://xx.xx.xx.xx:10091
    - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
      value: 1
    - name: KAFKA_CONFLUENT_LICENSE_TOPIC_REPLICATION_FACTOR
      value: 1
    - name: KAFKA_CONFLUENT_BALANCER_TOPIC_REPLICATION_FACTOR
      value: 1
    - name: KAFKA_TRANSACTION_STATE_LOG_MIN_ISR
      value: 1
    - name: KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR
      value: 1
    - name: CONFLUENT_METRICS_REPORTER_TOPIC_REPLICAS
      value: 1
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/kafka/log4j.properties
    # 追加
    volumeMounts: 
    - mountPath: /var/lib/kafka/data
      name: kafka-data
  - image: docker.io/xxxxxxxxx/cp-connector-jdbc-elasticsearch:latest
    name: ice-kafka-connect
    ports:
    - containerPort: 8083
      hostPort: 8083
    env:
    - name: CONNECT_BOOTSTRAP_SERVERS
      value: localhost:9092
    - name: CONNECT_LISTENERS
      value: http://0.0.0.0:8083
    - name: CONNECT_GROUP_ID
      value: ice-connect-cluster
    - name: CONNECT_CONFIG_STORAGE_TOPIC
      value: connect-configs
    - name: CONNECT_OFFSET_STORAGE_TOPIC
      value: connect-offsets
    - name: CONNECT_STATUS_STORAGE_TOPIC
      value: connect-statuses
    - name: CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR
      value: 1
    - name: CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR
      value: 1
    - name: CONNECT_STATUS_STORAGE_REPLICATION_FACTOR
      value: 1
    - name: CONNECT_KEY_CONVERTER
      value: io.confluent.connect.avro.AvroConverter
    - name: CONNECT_VALUE_CONVERTER
      value: io.confluent.connect.avro.AvroConverter
    - name: CONNECT_KEY_CONVERTER_SCHEMA_REGISTRY_URL
      value: http://localhost:8081
    - name: CONNECT_VALUE_CONVERTER_SCHEMA_REGISTRY_URL
      value: http://localhost:8081
    - name: CONNECT_INTERNAL_KEY_CONVERTER
      value: io.confluent.connect.avro.AvroConverter
    - name: CONNECT_INTERNAL_VALUE_CONVERTER
      value: io.confluent.connect.avro.AvroConverter
    - name: CONNECT_REST_ADVERTISED_HOST_NAME
      value: connect
    - name: CONNECT_PLUGIN_PATH
      value: /usr/share/confluent-hub-components
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/kafka/connect-log4j.properties 
  - image: docker.io/confluentinc/cp-schema-registry:7.0.1
    name: ice-schema-registry
    ports:
    - containerPort: 8081
      hostPort: 8081
    env:
    - name: SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS
      value: localhost:9092
    - name: SCHEMA_REGISTRY_LISTENERS
      value: http://0.0.0.0:8081
    - name: SCHEMA_REGISTRY_HOST_NAME
      value: schema-registry
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/schema-registry/log4j.properties
  - image: docker.io/confluentinc/cp-ksqldb-server:7.0.1
    name: ice-ksqldb-server
    ports:
    - containerPort: 8088
      hostPort: 8088
    env:
    - name: KSQL_BOOTSTRAP_SERVERS
      value: localhost:9092
    - name: KSQL_HOST_NAME
      value: ksqldb-server
    - name: KSQL_LISTENERS
      value: http://0.0.0.0:8088
    - name: KSQL_KSQL_SCHEMA_REGISTRY_URL
      value: http://localhost:8081
    - name: KSQL_KSQL_CONNECT_URL
      value: http://localhost:8083
    - name: KSQL_KSQL_LOGGING_PROCESSING_TOPIC_REPLICATION_FACTOR
      value: 1
    - name: KSQL_KSQL_LOGGING_PROCESSING_TOPIC_AUTO_CREATE
      value: true
    - name: KSQL_KSQL_LOGGING_PROCESSING_STREAM_AUTO_CREATE
      value: true
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/ksqldb-server/log4j.properties
  - image: docker.io/confluentinc/cp-enterprise-control-center:7.0.1
    name: ice-control-center
    ports:
    - containerPort: 9021
      hostPort: 9021
    env:
    - name: CONTROL_CENTER_BOOTSTRAP_SERVERS
      value: localhost:9092
    - name: CONTROL_CENTER_REPLICATION_FACTOR
      value: 1
    - name: CONTROL_CENTER_INTERNAL_TOPICS_PARTITIONS
      value: 1
    - name: CONTROL_CENTER_MONITORING_INTERCEPTOR_TOPIC_PARTITIONS
      value: 1
    - name: CONFLUENT_METRICS_TOPIC_REPLICATION
      value: 1
    - name: CONTROL_CENTER_CONNECT_CONNECT1_CLUSTER
      value: http://localhost:8083
    - name: CONTROL_CENTER_KSQL_KSQLDB1_URL
      value: http://localhost:8088
    - name: CONTROL_CENTER_SCHEMA_REGISTRY_URL
      value: http://localhost:8081
    - name: KAFKA_OPTS
      value: -Dlog4j.configuration=file:/etc/confluent-control-center/log4j.properties
  # 追加
  volumes:
  - name: zk-data
    hostPath:
      # ホストからボリュームをマッピングする場合、フルパス指定
      path: /mnt/vol1/zk-data
      type: Directory
  - name: zk-txn-logs
    hostPath:
      path: /mnt/vol2/zk-txn-logs
      type: Directory
  - name: kafka-data
    hostPath:
      path: /mnt/vol3/kafka-data
      type: Directory
```

- Pod再作成
```
$ sudo podman pod stop confluent
$ sudo podman pod rm confluent
$ sudo podman play kube ice-confluent-fix-add-pv.yaml
```

- マウントしたディレクトリにデータが書き込まれていることを確認
    - これでPodの再作成後もデータは失われない。
```
$ ls -l
合計 3104
drwxr-xr-x. 2 cloudadmin cloudadmin  4096  3月 22 13:10 __consumer_offsets-0
drwxr-xr-x. 2 cloudadmin cloudadmin  4096  3月 22 13:10 __consumer_offsets-1
drwxr-xr-x. 2 cloudadmin cloudadmin  4096  3月 22 13:10 __consumer_offsets-10
:
-rw-r--r--. 1 cloudadmin cloudadmin     4  3月 22 13:21 log-start-offset-checkpoint
-rw-r--r--. 1 cloudadmin cloudadmin    91  3月 22 13:10 meta.properties
-rw-r--r--. 1 cloudadmin cloudadmin 48931  3月 22 13:21 recovery-point-offset-checkpoint
-rw-r--r--. 1 cloudadmin cloudadmin 49084  3月 22 13:22 replication-offset-checkpoint
```