0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ROSA HCP で AWS ALB を使ってアプリを外部公開してみる

Last updated at Posted at 2025-09-10

0. はじめに

ROSA HCP の標準の Ingress として、AWS NLB がデプロイされています。また non-HTTPのTCPを使用したサービス用の Service Type=LoadBalancer としては、AWS CLB が個別アプリケーション毎にデプロイされます。

image.png
(わかりやすさのために TCP (non HTTP) と分けて書いてますが、HTTP も TCP上のプロトコルなので左側の方法で管理できます)

一方で、AWS の WAF を使いたいので、AWS ALBを使いたいなどの要件も出てくる事があります。
標準の NLB の前にAWSネットワーク設計などもろもろを駆使して ALB を設置する事もできますが、もっとシンプルに、ALBをデプロイするために、AWS謹製の AWS Load Balancer Contoler を使って ALB(Ingress)NLB(Service Type=LoadBalancer)をデプロイする事ができます。

OpenShift上では AWS Load Balancer Contoler を Operator 形式でパッケージしたAWS LoadBalancer OperatorOperator Hub上で提供されています。
image.png

OpenShift では必要の無い機能(例えば Fargate対応の mode) などはサポートしないようですが、Red Hatのサポートが受けられるパッケージという事でこちらを試して見ます。

オフィシャルドキュメントとしては、こちら、Red Hat の Cloud Service のエキスパート・チームである Black Belt チームが提供するサンプルはこちらと2通りのドキュメントが存在しています。

後者の方が必要な情報だけになっており、別途ツールも必要がなくわかり易いので、後者の手順に解説を付け加えたり、多少変更しながら手順をなぞって行こうと思います。

1. 前提

・ROSA HCP クラスターがインストール済み
・ROSA HCP クラスターは、3AZ 構成 ( AWS ALB は Single AZ 環境にはデプロイできない制限があるため)

2.環境変数の準備

環境変数を準備します。(全行コピーして一気に実行して問題ありません)

export ROSA_CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}"  | sed 's/-[a-z0-9]\{5\}$//')
export REGION=$(oc get infrastructure cluster -o=jsonpath="{.status.platformStatus.aws.region}")
export OIDC_ENDPOINT=$(oc get authentication.config.openshift.io cluster -o jsonpath='{.spec.serviceAccountIssuer}' | sed  's|^https://||')
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export SCRATCH="/tmp/${ROSA_CLUSTER_NAME}/alb-operator"
mkdir -p ${SCRATCH}

全ての環境変数がセットされている確認します。

echo "Cluster: ${ROSA_CLUSTER_NAME}, Region: ${REGION}, OIDC Endpoint: ${OIDC_ENDPOINT}, AWS Account ID: ${AWS_ACCOUNT_ID}"

3. VPC / Subnet へのタグ付け

サブネットに必要なタグ付けを行います。Subnet の ID は半角スペース区切りで並べます。

export VPC_ID=<vpc-id>
export PUBLIC_SUBNET_IDS=<public-subnets>
export PRIVATE_SUBNET_IDS=<private-subnets>
export CLUSTER_NAME=$(oc get infrastructure cluster -o=jsonpath="{.status.infrastructureName}")

AWS コンソールで ID を確認するのが面倒な場合は、以下の AWSコマンドで VPC ID / Subnet ID を取得できます。

aws ec2 describe-subnets \
  --query "Subnets[].{ID:SubnetId,Name:Tags[?Key=='Name']|[0].Value,VPC:VpcId}" \
  --output table

VPCにタグ付けします。

aws ec2 create-tags --resources ${VPC_ID} --tags Key=kubernetes.io/cluster/${CLUSTER_NAME},Value=owned --region ${REGION}

Public Subnet にタグ付けします

aws ec2 create-tags \
  --resources ${PUBLIC_SUBNET_IDS} \
  --tags Key=kubernetes.io/role/elb,Value='' \
  --region ${REGION}

Private Subnet にタグ付けします

aws ec2 create-tags \
  --resources ${PRIVATE_SUBNET_IDS} \
  --tags Key=kubernetes.io/role/internal-elb,Value='' \
  --region ${REGION}

4. AWS Load Balancer Contoler のインストール

新しいプロジェクト aws-load-balancer-operator を作成します。

oc new-project aws-load-balancer-operator

Operator 用の IAM Policy を作成します。既に存在していなければ、PIAM olicy を作成します。 IAM Policy の定義は AWS Load Balancer Controller の Github Repository から引っ張ってきています。

POLICY_ARN=$(aws iam list-policies --query \
  "Policies[?PolicyName=='aws-load-balancer-operator-policy'].{ARN:Arn}" \
  --output text)
if [[ -z "${POLICY_ARN}" ]]; then
  wget -O "${SCRATCH}/load-balancer-operator-policy.json" \
    https://raw.githubusercontent.com/openshift/aws-load-balancer-operator/main/hack/operator-permission-policy.json
  POLICY_ARN=$(aws --region "$REGION" --query Policy.Arn \
  --output text iam create-policy \
  --policy-name aws-load-balancer-operator-policy \
  --policy-document "file://${SCRATCH}/load-balancer-operator-policy.json")
fi
echo $POLICY_ARN

最期の POLICY_ARN の値が設定されている事を確認してください。

Operator の IAM Role 用の Trust Policy を作成します。

cat <<EOF > "${SCRATCH}/trust-policy.json"
{
  "Version": "2012-10-17",
  "Statement": [
  {
  "Effect": "Allow",
  "Condition": {
    "StringEquals" : {
      "${OIDC_ENDPOINT}:sub": ["system:serviceaccount:aws-load-balancer-operator:aws-load-balancer-operator-controller-manager", "system:serviceaccount:aws-load-balancer-operator:aws-load-balancer-controller-cluster"]
    }
  },
  "Principal": {
    "Federated": "arn:aws:iam::$AWS_ACCOUNT_ID:oidc-provider/${OIDC_ENDPOINT}"
  },
  "Action": "sts:AssumeRoleWithWebIdentity"
  }
  ]
}
EOF

Operator の IAM Role を作成し、先ほど作成した IAM Policy をアタッチします。

ROLE_ARN=$(aws iam create-role --role-name "${ROSA_CLUSTER_NAME}-alb-operator" \
--assume-role-policy-document "file://${SCRATCH}/trust-policy.json" \
--query Role.Arn --output text)
echo $ROLE_ARN

aws iam attach-role-policy --role-name "${ROSA_CLUSTER_NAME}-alb-operator" \
  --policy-arn $POLICY_ARN

Operator 用の Secret を作成します。

cat << EOF | oc apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: aws-load-balancer-operator
  namespace: aws-load-balancer-operator
stringData:
  credentials: |
    [default]
    role_arn = $ROLE_ARN
    web_identity_token_file = /var/run/secrets/openshift/serviceaccount/token
EOF

Operator をインストールします。

cat << EOF | oc apply -f -
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: aws-load-balancer-operator
  namespace: aws-load-balancer-operator
spec:
  upgradeStrategy: Default
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: aws-load-balancer-operator
  namespace: aws-load-balancer-operator
spec:
  channel: stable-v1.0
  installPlanApproval: Automatic
  name: aws-load-balancer-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace
  startingCSV: aws-load-balancer-operator.v1.0.0
EOF

ここで少し待ちます。以下のコマンドで Pod のデプロイが完了するまで待ちます。

watch oc get pods -n aws-load-balancer-operator

AWS Load Balancer Controller をインストールします。

cat << EOF | oc apply -f -
apiVersion: networking.olm.openshift.io/v1
kind: AWSLoadBalancerController
metadata:
  name: cluster
spec:
  credentials:
    name: aws-load-balancer-operator
EOF

以下のコマンドで状態を確認します。

oc -n aws-load-balancer-operator get pods

以下のようになれば完了です。

$ oc -n aws-load-balancer-operator get pods
NAME                                                             READY   STATUS    RESTARTS   AGE
aws-load-balancer-controller-cluster-84b6b57d55-zmmfg            1/1     Running   0          8m
aws-load-balancer-operator-controller-manager-76bfdbd7b4-k97vd   2/2     Running   0          8m
$ 

5. サンプルアプリのデプロイ

ここでは、EchoServer (HTTP) のアプリをデプロイしてみます。
サンプルのアプリは GitHub の AWS LoadBalancer Controllerの Repository のものを使用します。

5.1 ALB と HTTP アプリのデプロイ

echoserver という namespace を作成します。

oc apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/examples/echoservice/echoserver-namespace.yaml

このサンプルアプリは、OpenShift にデプロイするには、要求する権限が大きいので、OpenShift 側の権限を緩めます。(anyuid を許可)

oc adm policy add-scc-to-user anyuid system:serviceaccount:echoserver:default

以下のファイルを apply して DeploymentServiceechoserver namespace にデプロイします。

oc apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/examples/echoservice/echoserver-deployment.yaml
oc apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/examples/echoservice/echoserver-service.yaml
oc apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/examples/echoservice/echoserver-ingress.yaml

以上で Ingress を使ってアプリが公開されました。

デプロイの完了まで数分程度あると思うので、ServiceIngress の中身を確認しておきます。

ServiceNodePort になっています。

echoserver-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: echoserver
  namespace: echoserver
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
  type: NodePort
  selector:
    app: echoserver

OpenShiftの標準の IngressController の場合は、クラスター内の Router PodNLBからNodePort で一旦トラフィックを受け、 HTTP Header のドメイン名を見て、適切な Application Pod の IP にトラフィックをフォワードします。そのため、各 Application PodNodePortServiceを使いません。
一方、AWS LoadBalancer Controllerの場合は、ALBが 各 Application PodNodePortにトラフィックを渡します。

Ingress は、annotatins:spec.ingressClassName: が必要です。

echoserver-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: echoserver
  namespace: echoserver
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/tags: Environment=dev,Team=test
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: /
            pathType: Exact
            backend:
              service:
                name: echoserver
                port:
                  number: 80

この Ingress リソースを AWS LoadBalance Controller で処理してもらうためには、spec.ingressClassName: alb が必要で、annotations も正しく設定されている必要があります。
OpenShift も Ingress リソースを処理できるため、spec.ingressClassName が指定されて無い場合は、OpenShift が Ingress リソースを処理しようとします。

Ingress がデプロイされている事を確認します。

oc -n echoserver get ingress echoserver

以下のような出力になるはすです

$ oc -n echoserver get ingress echoserver
NAME         CLASS   HOSTS   ADDRESS                                                                       PORTS   AGE
echoserver   alb     *       k8s-echoserv-echoserv-94b1c3792d-970404549.ap-northeast-1.elb.amazonaws.com   80      73m
$ 

アプリがデプロイされている事を確認します。

 oc -n echoserver get pods

以下のような出力になるはずです。

$ oc -n echoserver get pods
NAME                         READY   STATUS    RESTARTS   AGE
echoserver-658d7b6fb-rvnk4   1/1     Running   0          4m14s
$ 

アプリにアクセスしてみます。

INGRESS=$(oc -n echoserver get ingress echoserver \
  -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
  
curl -sH "Host: ${INGRESS}"  "http://${INGRESS}" | grep Hostname

このアプリケーションは、送信した HTTPリクエストをそのまま Response で返してきます。
以下のような出力になるはずです。

$ curl -sH "Host: ${INGRESS}"  "http://${INGRESS}" | grep Hostname
Hostname: echoserver-658d7b6fb-zxpjh
$ 

(ALBがきちんと立ちあがったように見えても、反応が返って来ない(空のレスポンス)の場合があります。その場合は4分程度待ってみてください)

5.2 NLB と TCPアプリ (non HTTP) をデプロイ

今度は、TCP (non HTTP) の echoserver Pod デプロイして、Service Type=LoadBalancer を使って外部公開してみます。

アプリは私の GitHub repository のものを使います。(中身は nc コマンドを実行しているだけですが、心配な方は deploymentで確認できます。怪しくないよ)

tcp-echo という namespace を作成します。

oc apply -f https://raw.githubusercontent.com/yuhkih/tcp-echo/refs/heads/main/namespace.yaml

Deployment で tcp echoserver Pod をデプロイし。Service Typle=LoadBalancerでアプリを公開します。

oc apply -f https://raw.githubusercontent.com/yuhkih/tcp-echo/refs/heads/main/deployment.yaml
oc apply -f https://raw.githubusercontent.com/yuhkih/tcp-echo/refs/heads/main/service-aws-lb-operator.yaml

暫くするとアクセス可能になりますが、その間に、Service Type=LoadBalcer の中身を確認しましょう。
annotations: の部分に注目して下さい。

service-aws-lb-operator.yaml
apiVersion: v1
kind: Service
metadata:
  name: echoserver-nlb
  namespace: echoserver
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: external
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: instance
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
  type: LoadBalancer
  selector:
    app: echoserver

annotations がある事で AWS LoadBalancer ControllerService リソースを処理して NLB が作成されます。
annotations が無い場合は、OpenShift がこのリソースを処理して、CLBが作成されます。

以下のコマンドでデプロイを確認してみます。

oc -n tcp-echo get service tcp-echo

以下のような出力が出てくるはずです。

$ oc -n tcp-echo get service tcp-echo
NAME       TYPE           CLUSTER-IP       EXTERNAL-IP                                                                 
       PORT(S)          AGE
tcp-echo   LoadBalancer   172.30.139.153   k8s-tcpecho-tcpecho-ab3f09303e-1ed39f83c61b86b7.elb.ap-northeast-1.amazonaws.com   9000:30610/TCP   14m
$ 

アプリにアクセスしてみます。

NLB=$(oc -n tcp-echo get service tcp-echo \
  -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
nc ${NLB} 9000

以下のように入力した文字列と同じ文字列が出力で返ってくるはずです。

$ nc ${NLB} 9000
aaa
aaa
Hello!
Hello!
...
(Ctrl + C で終了) 

(NLBがきちんと立ちあがったように見えても、ドメインが解決できなかったり、echo が返って来ない場合があります。その場合は4分程度待ってみてください)

6. 構成のまとめ

今回、ざっとドキュメントをなめてみたり、実機で確認した限りでは、AWS Load Balancer Operator (と大元の AWS Load Balancer Controller) では、アプリ一つにつき、1つの Load Balancerがデプロイされるようです。

image.png

コストや要件の違いで、ROSA デフォルト構成で使われる ELB と、AWS Load Balancer Operator (AWS Load Balancer Controller) でデプロイされる ELBを使いわける事になると思います。

また、Default の NLB ではなく、ALB を使いたいという要件の多くは、恐らく WAF 等を使いたいという所から来ると想像しますが、指定は annotation でできるようです。

尚、上記の図にはスペースの都合で書いてませんが、AWS Load Balancer Operator を使う場合でも、ROSA HCP デフォルトでデプロイされる NLB は削除する事はできません。

7. 環境の Clean Up

echoserver アプリを削除します

oc delete project echoserver
oc delete project tcp-echo

Operator 用の AWS Role を削除します

aws iam detach-role-policy \
  --role-name "${ROSA_CLUSTER_NAME}-alb-operator" \
  --policy-arn $POLICY_ARN
aws iam delete-role \
  --role-name "${ROSA_CLUSTER_NAME}-alb-operator"

Operator 用の IAM Policyを削除します。

aws iam delete-policy --policy-arn $POLICY_ARN

Operator を導入した namespace を削除します。

oc delete project aws-load-balancer-operator

8. 補足

AWS Console を開かずに、作成された ELB の確認を AWS CLI から行う方法として以下があります。

ALB / NLB の場合

aws elbv2 describe-load-balancers   --query 'LoadBalancers[*].[LoadBalancerName,Type,DNSName, VpcId]'   --output table

CLB の場合

aws elb describe-load-balancers --region ap-northeast-1  --query 'LoadBalancerDescriptions[*].[LoadBalancerName,DNSName, VPCId]'   --output table

9. 参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?