はじめに
今回は、以下の構成で2時間で動く本格的なREST APIアプリケーションをIBM製品を用いて作成します。
前半と後半に分けて、実践していきます。
前半(本記事) 👈 今回はこちら!
- OpenShift環境の準備
- PostgreSQLのデプロイ
- Nginxコンテナのデプロイと動作確認
後半(次回)
- Open LibertyによるREST API実装
- データベース連携
- 完全なCRUD操作の実装
この記事で学べること
- OpenShift上でのコンテナアプリケーションのデプロイ方法
- PostgreSQLデータベースの構築と接続
- OpenShiftリソース(Route、Service、Pod)の理解
- エンタープライズグレードのインフラ構築の基礎
あなたのPC → OpenShift上のREST API → PostgreSQLデータベース
構成
全て一気にやろうとすると自分の理解が追いつかないので、まずはシンプルな構成で全体像を理解した上で(前半)、OpenLibertyを導入します(後半)。
最終的に構築するシステム
┌──────────────────────────────────────────────────┐
│ あなたのPC │
│ • Postman / curl / ブラウザ │
└─────────────────┬────────────────────────────────┘
│ HTTPS
↓
┌──────────────────────────────────────────────────┐
│ IBM TechZone - OpenShift Cluster (OCP-V) │
│ IBM Cloud上で動作(完全無料) │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Route (外部公開URL) │ │
│ │ https://liberty-api-xxx.apps.xxx.cloud │ │
│ └─────────────────┬────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Open Liberty Pods (2個) │ │
│ │ • REST API (GET/POST/PUT/DELETE) │ │
│ │ • Java 11 / Jakarta EE │ │
│ │ • 自動スケーリング │ │
│ └─────────────────┬────────────────────────────┘ │
│ │ JDBC │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ PostgreSQL Pod │ │
│ │ • 永続ボリューム (1GB) │ │
│ │ • 自動バックアップ │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
前半編で構築する範囲
┌──────────────────────────────────────────────────┐
│ あなたのPC │
│ • ブラウザ / curl │
└─────────────────┬────────────────────────────────┘
│ HTTPS
↓
┌──────────────────────────────────────────────────┐
│ OpenShift Cluster │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Route (外部公開URL) │ │
│ │ https://my-api-app-xxx.apps.xxx.cloud │ │
│ └─────────────────┬────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ HTTPD Pods (2個) │ │
│ │ • Apache HTTP Server 2.4 │ │
│ │ • 静的コンテンツ配信 │ │
│ │ • 環境変数でDB接続情報を保持 │ │
│ └─────────────────┬────────────────────────────┘ │
│ │ (接続準備のみ) │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ PostgreSQL Pod │ │
│ │ • PostgreSQL 13 │ │
│ │ • データベース: apidb │ │
│ │ • ユーザー: apiuser │ │
│ │ • 永続ボリューム: 1GB │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
前半の手順概要
所要時間
ステップ1: TechzoneでOpenShift環境予約 30分 (+ 承認待ち 1-2日)
ステップ2: Openshift上でPostgreSQLデプロイ 5分
ステップ3: Openshift上でLibertyアプリデプロイ 10分
合計: 45分 (承認待ち除く)
ステップ1: OpenShift環境の予約
1.1 IBM TechZoneアカウント作成
ステップ2: PostgreSQLのデプロイ
2.1 OpenShift CLIのインストール
macOS
brew install openshift-cli
2.2 OpenShiftへのログイン
Openshiftへ、ocコマンドを使ってログインします。
oc login --token=sha256~xxxxx --server=https://xxxxx:6443
確認:
oc whoami
# 出力: IAM#your-email@example.com
oc version
# 出力: OpenShift Version: 4.x.x
2.3 プロジェクトの作成
# プロジェクト作成
oc new-project my-api-project
# 確認
oc project
# 出力: Using project "my-api-project"
2.4 PostgreSQLのデプロイ
Openshift上で、PostgreSQLをデプロイしていきます。
# PostgreSQLをデプロイ(永続ボリューム付き)
oc new-app postgresql-persistent \
-p POSTGRESQL_USER=apiuser \
-p POSTGRESQL_PASSWORD=SecurePass123! \
-p POSTGRESQL_DATABASE=apidb \
-p VOLUME_CAPACITY=1Gi \
-p POSTGRESQL_VERSION=13-el8
# デプロイ確認(起動まで1-2分)
oc get pods -w
# Ctrl+C で終了
# 起動完了の確認
oc get pods | grep postgresql
# 出力例: postgresql-1-xxxxx 1/1 Running 0 2m

デプロイが確認できました。
「PostgreSQLのデプロイ、こんなに簡単に?」と思いIBM Bobに聞いてみたところ、Openshiftには、よく使うアプリケーションのテンプレが事前用意されていて、それを使うとデプロイができるようになっているようです。
ここでは、データベースサーバーを作るように、データベースアプリケーションスタック(複数コンポーネントの塊)をテンプレを使って作成し、DB機能を持たせています。
2.5 接続情報の確認
# Serviceを確認
# Serviceは、Podへのネットワークアクセスを提供する抽象化レイヤ。k8sでいうリソース。
oc get svc postgresql
# 出力例:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# postgresql ClusterIP 172.30.113.76 <none> 5432/TCP 2m
接続情報の確認として、Serviceを確認します。Serviceリソースがあることで、Podが再起動してIPアドレスが変わっても、Serviceが固定のDNS名とIPが保たれるのですね!
ステップ3: Libertyアプリケーションのデプロイ
3.1 Liberty Operatorのインストール
OpenShift Webコンソールで実行:
- OpenShift Webコンソールにログイン
- URL: メールに記載
- 左メニュー "Operators" → "OperatorHub"
- 検索: "Open Liberty"
- "Open Liberty Operator" を選択
- "Install" をクリック
- 設定:
- Installation Mode: All namespaces
- Update Channel: stable
- "Install" をクリック
- インストール完了まで 2-3分 待機
3.2 YAMLファイルを使用したデプロイ(推奨)
cat <<EOF | oc apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-api-app
namespace: my-api-project
labels:
app: my-api-app
spec:
replicas: 2
selector:
matchLabels:
app: my-api-app
template:
metadata:
labels:
app: my-api-app
spec:
containers:
- name: nginx
image: image-registry.openshift-image-registry.svc:5000/openshift/nginx:latest
ports:
- containerPort: 8080
protocol: TCP
env:
- name: DB_HOSTNAME
value: "postgresql.my-api-project.svc.cluster.local"
- name: DB_PORT
value: "5432"
- name: DB_USERNAME
value: "apiuser"
- name: DB_PASSWORD
value: "SecurePass123!"
- name: DB_NAME
value: "apidb"
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
name: my-api-app
namespace: my-api-project
spec:
selector:
app: my-api-app
ports:
- name: http
port: 8080
targetPort: 8080
type: ClusterIP
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: my-api-app
namespace: my-api-project
spec:
to:
kind: Service
name: my-api-app
port:
targetPort: http
tls:
termination: edge
insecureEdgeTerminationPolicy: Redirect
EOF
参考: https://github.com/OpenLiberty/open-liberty-operator
3.3 デプロイの確認
# Podの状態を確認
oc get pods
# 出力例:
# NAME READY STATUS RESTARTS AGE
# my-api-app-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
# my-api-app-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
# postgresql-1-xxxxx 1/1 Running 0 5m
新たなコンテナが作られました。起動まで 3-5分 かかります。
app=my-api-appで絞って確認できました。

3.4 外部URLの取得
## 1.外部URL(RouteのURL)を取得
# RouteのURLを取得
oc get route my-api-app -o jsonpath='{.spec.host}'
# 出力例:
# my-api-app-my-api-project.apps.xxxxx.cloud.ibm.com
## 2.動作確認
# 環境変数に設定
export APP_URL=$(oc get route my-api-app -o jsonpath='{.spec.host}')
# アクセステスト
curl https://$APP_URL
# 期待される出力:
# Nginxのウェルカムページ
このコマンドによって、OpenShift内部のアプリケーションを外部からアクセスできるURLを取得しました。
外部URLをWebブラウザに貼ると、無事テストページが表示されました。

Routeとは?
OpenshiftでいうRouteとは、外部公開の入口となるリソースです。これがないと、外部からOpenshift内部へアクセスできなくなります。
┌─────────────────────────────────────────────────────────┐
│ あなたのPC(外部) │
│ ブラウザ / curl │
└──────────────────┬──────────────────────────────────────┘
│
│ ① インターネット経由でアクセス
│ https://my-api-app-xxx.apps.xxx.cloud.ibm.com
↓
┌─────────────────────────────────────────────────────────┐
│ OpenShift Cluster(内部) │
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ Route(外部公開の入口) │ │
│ │ Host: my-api-app-xxx.apps.xxx.cloud.ibm.com │ │
│ │ TLS: edge(HTTPS終端) │ │
│ └──────────────────┬─────────────────────────────┘ │
│ │ │
│ │ ② 内部のServiceに転送 │
│ ↓ │
│ ┌────────────────────────────────────────────────┐ │
│ │ Service: my-api-app │ │
│ │ Type: ClusterIP │ │
│ │ IP: 172.30.xxx.xxx(内部IPアドレス) │ │
│ │ Port: 8080 │ │
│ └──────────────────┬─────────────────────────────┘ │
│ │ │
│ │ ③ Podに転送 │
│ ┌──────────┴──────────┐ │
│ ↓ ↓ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Pod 1 │ │ Pod 2 │ │
│ │ HTTPD │ │ HTTPD │ │
│ │ Port: 8080 │ │ Port: 8080 │ │
│ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
一旦ここまでで、どういった全体像になっているか確認してみます!
以下で、「インターネットからアクセスして、アプリがデータベースを使う」という流れを、OpenShiftのリソースで実現しています。
ブラウザでアクセスすると入り口のRouteにアクセスがいって、Routeから振り分け係のService→実際にアプリけーっションが動く場所であるPodという流れです。
リソース 役割 例え
- Route:外部からの入口 マンションの玄関
- Service:振り分け係 受付・ホールスタッフ
- Pod:実際に働く場所 部屋・厨房
- PostgreSQL:データ保管 倉庫・図書館
┌─────────────────────────────────────────────────────────────┐
│ 外部(インターネット) │
│ https://my-api-app-xxx.apps.xxx.cloud.ibm.com │
└──────────────────────┬──────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ OpenShift Cluster │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Namespace: my-api-project │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ Route: my-api-app │ │ │
│ │ │ • Host: my-api-app-xxx.apps.xxx.cloud │ │ │
│ │ │ • TLS: edge │ │ │
│ │ └──────────────────┬──────────────────────────────┘ │ │
│ │ │ │ │
│ │ ↓ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ Service: my-api-app │ │ │
│ │ │ • Type: ClusterIP │ │ │
│ │ │ • IP: 172.30.xxx.xxx │ │ │
│ │ │ • Port: 8080 │ │ │
│ │ │ • Selector: app=my-api-app │ │ │
│ │ └──────────────────┬──────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────┴──────────┐ │ │
│ │ ↓ ↓ │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Pod 1 │ │ Pod 2 │ │ │
│ │ │ HTTPD │ │ HTTPD │ │ │
│ │ │ 10.129.x.x │ │ 10.131.x.x │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ │ │
│ │ │ │ │ │
│ │ │ DB接続(環境変数) │ │ │
│ │ └──────────┬──────────┘ │ │
│ │ │ │ │
│ │ ↓ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ Service: postgresql │ │ │
│ │ │ • Type: ClusterIP │ │ │
│ │ │ • IP: 172.30.113.76 │ │ │
│ │ │ • Port: 5432 │ │ │
│ │ │ • DNS: postgresql.my-api-project.svc.cluster... │ │ │
│ │ └──────────────────┬──────────────────────────────┘ │ │
│ │ │ │ │
│ │ ↓ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ Pod: postgresql-1-44f9b │ │ │
│ │ │ • PostgreSQL 13 │ │ │
│ │ │ • IP: 10.131.0.91 │ │ │
│ │ │ • Port: 5432 │ │ │
│ │ │ • Volume: /var/lib/pgsql/data │ │ │
│ │ └──────────────────┬──────────────────────────────┘ │ │
│ │ │ │ │
│ │ ↓ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ PersistentVolumeClaim: postgresql │ │ │
│ │ │ • Size: 1Gi │ │ │
│ │ │ • Status: Bound │ │ │
│ │ └──────────────────┬──────────────────────────────┘ │ │
│ │ │ │ │
│ │ ↓ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ PersistentVolume │ │ │
│ │ │ • IBM Cloud Block Storage │ │ │
│ │ │ • 1GB │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ Secret: postgresql │ │ │
│ │ │ • database-user │ │ │
│ │ │ • database-password │ │ │
│ │ │ • database-name │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
🔧 トラブルシューティング
問題1: Podが起動しない
# ログを確認
oc logs <pod-name>
# イベントを確認
oc describe pod <pod-name>
# リソース不足の場合
oc get nodes
oc describe node <node-name>
問題2: ImagePullBackOff エラー
症状:
NAME READY STATUS RESTARTS AGE
my-api-app-xxxxxxxxxx-xxxxx 0/1 ImagePullBackOff 0 2m
原因:
- Docker Hubのレート制限に達した
- イメージが存在しない
解決方法:
# OpenShift内部レジストリのイメージを使用
# liberty-app.yaml のイメージを以下に変更:
# image: image-registry.openshift-image-registry.svc:5000/openshift/nginx:latest
# または、既存のデプロイメントを削除して再デプロイ
oc delete deployment my-api-app
oc apply -f liberty-app.yaml

自分はこの問題2のエラーにハマりました。既存のデプロイメントを削除して、再度デプロイしたら直りました。
一時的にErrorが出ているのは、ローリングアップデートで古いpodが削除されているからです。
さいごに
思ったより理解に時間がかかりましたが、Openshiftの理解が深まりました。特に、WebアプリケーションをデプロイするうえでOpenshiftがとる大まかな構成が新しく知れました。
現在はHTTPDのみで、REST APIはまだ実装されていません。次のステップでREST APIアプリケーションを実装する必要があります!



