デスクトップからクラウドへ：Podman と OpenShift で始める簡単コンテナ開発

## **1. はじめに**

近年、コンテナ技術はアプリケーション開発の中心に位置づけられ、効率的な開発やデプロイを支える強力な手段となっています。その中でも、デスクトップ環境での簡単なコンテナビルドから、Kubernetes ベースのプラットフォームである OpenShift による運用までをシームレスに行えることは、多くの開発者にとって大きな魅力です。2024年を振り返っても、こういった紹介をしたり目にしたりする機会が多かったことから、より一般的なユースケースとして定着してきた印象があります。

この記事では、手軽に始められる「**デスクトップ環境でアプリをビルドし、最終的に OpenShift 上で動作させる**」という一連の流れを紹介します。特に、Podman を活用することで Kubernetes マニフェストの自動生成まで行えるため、開発者が効率的に作業を進められるポイントに注目しています。

本記事ではサンプルアプリを使用しますが、同じ手順をカスタムアプリに適用することで、より深い理解を得られるでしょう。

では、さっそく始めてみましょう！

## **2. デスクトップで始めるコンテナ開発: Podman の活用**

コンテナ開発を始める際、まずはローカル環境での実験が重要です。ここでは、軽量で手軽に使えるコンテナ管理ツール「**Podman**」を活用し、簡単なコンテナ開発を始める方法を紹介します。

### **Podman とは？**
Podman は、Docker と互換性のあるコマンドラインツールで、コンテナのビルド・実行・管理を行うためのオープンソースプロジェクトです。その特徴として、デーモンレスで動作するため、セキュリティやリソース効率の面で優れています。また、Kubernetes マニフェストの自動生成機能を持っており、クラウド環境への展開もスムーズに行えます。

### **コンテナイメージを作成する**
まず、以下のような簡単な Node.js アプリケーション（`server.js`）を用意します。

**作業ディレクトリ作成**
任意の作業ディレクトリを作成し、そこで各種ファイルを作成して作業をすすめます。
``` mkdir & cd
$ mkdir MyHelloApp_Node_js
$ cd MyHelloApp_Node_js
```

**server.js**
```javascript
const http = require('http');
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello from Podman!\n');
});
server.listen(8080, () => {
  console.log('Server running on http://localhost:8080');
});
```

次に、このアプリをコンテナ化するための `Containerfile` を作成します。

**Containerfile**
```Containerfile
FROM node:18
WORKDIR /app
COPY server.js .
CMD ["node", "server.js"]
```

**カレントディレクトリのファイルレイアウト**
``` tree
$ tree
.
├── Containerfile
└── server.js

1 directory, 2 files
```

Podman を使用してイメージをビルドします。
```bash
podman build -t sample-app .
```

### **ローカルでコンテナを実行する**
イメージをビルドしたら、以下のコマンドでコンテナを起動します。
```bash
podman run -d --name my-sample-app -p 8080:8080 sample-app
```

ブラウザで `http://localhost:8080` にアクセスすると、「Hello from Podman!」が表示されるはずです。


## **3. マニフェストの作成: アプリケーションの定義**

ローカル環境で動作確認したアプリケーションを Kubernetes や OpenShift にデプロイするためには、その定義を YAML 形式のマニフェストとして記述する必要があります。マニフェストは、アプリケーションの構成情報をコードとして管理し、再現性やスケーラビリティを確保するための重要な役割を担います。

とはいえ、初めてマニフェストを手作業で作成するのは少し敷居が高いかもしれません。ここで役立つのが、Podman の `generate kube` 機能です。このコマンドを使えば、ローカル環境で実行中のコンテナから Pod の定義だけでなく、アプリケーションを外部に公開するための Service を含むマニフェストを簡単に生成できます。

### **Pod と Service を含むマニフェストを生成する**
まずは、前のセクションで起動したコンテナ（`my-sample-app`）を基に、以下のコマンドを実行します。
```bash
podman generate kube --service my-sample-app > app-deployment.yaml
```

`generate kube`に、`--service`を指定することで、Pod の定義に加え、コンテナで公開しているポート（例: 8080）を基に Service リソースも自動的に生成することができます。

### **Service を追加する理由**
Kubernetes 環境では、Pod は可変的なリソースであり、再起動やスケール変更のたびに IP アドレスが変わります。そのため、安定した通信を可能にするための固定的なエンドポイントを提供する **Service** が必要になります。

また、Service を使用することで以下のようなメリットが得られます。
- **内部通信の安定化**: クラスター内での他のリソースからのアクセスを簡単に
- **外部公開の手段**: 外部クライアントがアプリケーションに接続するための窓口を提供

### **生成されたマニフェストの中身を確認する**
以下は、生成されたマニフェストの例です。

**app-deployment.yaml**
```yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-sample-app
spec:
  containers:
  - name: my-sample-app
    image: localhost/sample-app:latest
    ports:
    - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: my-sample-app
spec:
  selector:
    name: my-sample-app
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
```

このように、Pod の定義に加えて、Pod を公開するための Service が追加されています。



## **4. OpenShift にデプロイ: クラウド環境での実行**

これまでにローカルで動作させたアプリケーションを OpenShift環境で実行するには、作成したマニフェストを OpenShift に適用する必要があります。OpenShift は Kubernetes をベースにしたプラットフォームであり、Pod、Service などのリソースを簡単に管理できる機能を提供します。

### **OpenShift クラスタへの接続**
まずは OpenShift のクラスタに接続し、適切なプロジェクト（名前空間）を選択します。もし OpenShift クラスタにまだアクセスしていない場合、以下のコマンドで接続できます。

```bash
oc login -u developer https://api.crc.testing:6443 
```

次に、アプリケーションをデプロイするプロジェクトを作成または選択します。例えば、新しいプロジェクトを作成する場合は次のようにします。

```bash
oc new-project my-sample-project
```

### **コンテナイメージのイメージレジストリへの登録**

コンテナをOpenShift環境上で取得して展開出きるようにしたいので、**2. デスクトップで始めるコンテナ開発: Podman の活用** で作成したコンテナイメージをOpenShift上のローカルレジストリに登録します。

#### **イメージレジストリのURLの確認**
OpenShift上のイメージレジストリのURLを確認します。既にURLが分かる場合は個の操作はスキップしても問題ありません。

```bash
# OpenShift local の場合のログイン例
# ローカルのイメージレジストリが稼働しているnamespaceへのアクセスには管理者権限が必要のため、管理者
# アカウントで接続しています。
$ oc login -u kubeadmin https://api.crc.testing:6443
# クレデンシャル情報がない場合は、ログイン時にプロンプトからパスワードの入力が必要となります。


# ネームスペース "openshift-image-registry" の ルートを参照することで、イメージレジストリ
# のURLを確認できます。
$ oc get routes -n openshift-image-registry
NAME            HOST/PORT                                                 PATH   SERVICES         PORT    TERMINATION   WILDCARD
default-route   default-route-openshift-image-registry.apps-crc.testing          image-registry   <all>   reencrypt     None
$ 

# OpenShift セッションを"developer"へ戻します。
$ oc login -u developer https://api.crc.testing:6443
```

#### **コンテナイメージのプッシュ**
podman コマンドを使用して、コンテナイメージをOpenShift 上のコンテナレジストリへプッシュします。

```bash
# podman コマンドで、OpenShift 上のイメージレジストリへログイン
$ podman login -u $(oc whoami) -p $(oc whoami -t) --tls-verify=false default-route-openshift-image-registry.apps-crc.testing

# イメージにタグ情報を付与
$ podman tag sample-app:latest default-route-openshift-image-registry.apps-crc.testing/my-sample-project/my-sample-app:latest

# イメージをプッシュ
$ podman push --tls-verify=false default-route-openshift-image-registry.apps-crc.testing/my-sample-project/my-sample-app:latest
```

#### **マニフェストの修正**
**3.マニフェストの作成: アプリケーションの定義**で生成されたマニフェストは、imageの指定がlocalhost となっています。ここでは、OpenShift上のレジストリからimage を取得するようにしたいので、以下の様に変更します。

```yaml
# <変更前
    image: localhost/sample-app:latest

# 変更後
    image: default-route-openshift-image-registry.apps-crc.testing/my-sample-project/my-sample-app:latest
```

### **マニフェストの適用**
次に、先ほど作成した `app-deployment.yaml` ファイルを OpenShift クラスタに適用します。このマニフェストには、Pod と Service が定義されています。以下のコマンドで適用を実行します。

```bash
oc apply -f app-deployment.yaml
```

これにより、Pod と Service が OpenShift クラスタ上にデプロイされます。`oc apply` コマンドは Kubernetes でいうところの `kubectl apply` と同様に、リソースの作成や更新を行います。

### **デプロイ状況の確認**
デプロイが成功すると、OpenShift 上でリソースの状態を確認することができます。まず、Pod が正常に立ち上がっているかを確認するには次のコマンドを実行します。

```bash
oc get pods
```

正常に起動していれば、`my-sample-app` の Pod がステータス `Running` で表示されるはずです。

次に、Service が正しく作成されたかを確認します。

```bash
oc get svc
```

これにより、公開された Service の詳細を確認できます。例えば、Service が `8080` ポートで公開されていれば、他の Pod からこのサービスにアクセスすることができます。

### **アプリケーションの公開とアクセス**

service公開し、アクセスできることを確認します。

```bash
$ oc expose svc/my-sample-app-pod
$ oc get route my-sample-app-pod --output jsonpath={.spec.host}
my-sample-app-pod-my-sample-project.apps-crc.testing

# 今回のアプリで、上記の様な出力となる場合、以下のコマンドでアクセスします。
# $ curl http://my-sample-app-pod-my-sample-project.apps-crc.testing
# Hello from Podman!
# $
```

以上、この記事では、簡単なアプリケーションを作成から、podman でコンテビルド＆実行の確認、podman のサブコマンドによるkubernetesマニフェスト生成の後、OpenShift 上にデプロイするまでを見てきました。

コンテナアプリ開発の参考としてもらえればと思います。

### 追記：参考情報など
[Openshift Local インストール&セットアップ Dec-2024版](https://qiita.com/Taraki1978/items/b8dfd1b96240c6110fe3)：この記事で取り上げたOpenShift Local のインストール＆セットアップ方法を記事にしました。