AWS IngressのAnnotationであるalb.ingress.kubernetes.io/group.nameを使ってALB1つにクラスタ上のサービスを相乗りさせてALB代を節約する

## 説明
- `alb.ingress.kubernetes.io/group.name`はAWS Load Balancer Controlerから使うことができるIngressリソースのAnnotation
- https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/ingress/annotations/#group.name
- 特徴
    - 今まで、1Ingressに1ALBという1対1の関係でデプロイされていたが、これをn対1にすることができる
    - そうすることで、単純にコストを押させることができる
    - 1つに集約するため、その分可用性は失われるので、本番環境では一考したほうがいいかもしれない

## 検証
namspaceを2つ作成し、別々のアプリをデプロイし、それぞれにルーティングされるかを見たい

### それぞれのアプリの準備

```
mkdir yellow/ green/
```


Yellowアプリ
```
echo '<html style="background-color: green;"></html>' > green/index.html
cat <<EOF > green/Dockerfile
FROM public.ecr.aws/nginx/nginx:1.20-alpine
RUN mkdir -p /usr/share/nginx/html/green
COPY ./index.html /usr/share/nginx/html/green/index.html
EXPOSE 80
EOF

# ECRリポジトリを作る
aws ecr create-repository --repository-name green
```

Greenアプリ

```
echo '<html style="background-color: green;"></html>' > green/index.html
cat <<EOF > green/Dockerfile
FROM public.ecr.aws/nginx/nginx:1.20-alpine
RUN mkdir -p /usr/share/nginx/html/green
COPY ./index.html /usr/share/nginx/html/green/index.html
EXPOSE 80
EOF

# ECRリポジトリを作る
aws ecr create-repository --repository-name green
```

ECRへログイン
```
export AWS_REGION=$(aws ec2 describe-availability-zones --output text --query 'AvailabilityZones[0].[RegionName]')
export AWS_REGISTRY_ID=$(aws ecr describe-registry --query registryId --output text)
export AWS_ECR_REPO=${AWS_REGISTRY_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com

aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ECR_REPO
```

Yellowアプリのビルド&Push
```
cd yellow/
docker build . -t yellow
docker tag yellow:latest $AWS_ECR_REPO/yellow:latest
docker push $AWS_ECR_REPO/yellow:latest
cd ..
```

Greenアプリのビルド&Push
```
export AWS_REGION=$(aws ec2 describe-availability-zones --output text --query 'AvailabilityZones[0].[RegionName]')
export AWS_REGISTRY_ID=$(aws ecr describe-registry --query registryId --output text)
export AWS_ECR_REPO=${AWS_REGISTRY_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com

aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ECR_REPO
```



### マニフェストファイル

Yellowアプリ用


```color-app-deployment-1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: yellow-app
  namespace: color-app-1
  labels:
    app: yellow-app
spec:
  selector:
    matchLabels:
      app: yellow-app
  replicas: 2
  template:
    metadata:
      labels:
        app: yellow-app
    spec:
      containers:
      - name: yellow-container
        image: 697333814333.dkr.ecr.ap-northeast-1.amazonaws.com/yellow:latest
        ports:
            - containerPort: 80
        resources:
          limits:
            memory: "100Mi"
            cpu: "200m"
```

```color-app-service-1.yaml
apiVersion: v1
kind: Service
metadata:
  namespace: color-app-1
  name: yellow-service
  labels:
    app: yellow-app
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: /yellow/index.html
spec:
  type: NodePort
  selector:
    app: yellow-app
  ports:
    - port: 80
      targetPort: 80
```


```color-app-ingress-1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: color-app-ingress
  namespace: color-app-1
  labels:
    app: color-app
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
    alb.ingress.kubernetes.io/healthcheck-port: traffic-port
    alb.ingress.kubernetes.io/healthcheck-interval-seconds: '15'
    alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '5'
    alb.ingress.kubernetes.io/success-codes: '200'
    alb.ingress.kubernetes.io/healthy-threshold-count: '2'
    alb.ingress.kubernetes.io/unhealthy-threshold-count: '2'
    alb.ingress.kubernetes.io/group.name: color-group
    external-dns.alpha.kubernetes.io/hostname: color-app-1.vamdemic.xyz
spec:
  rules:
    - host: "color-app-1.vamdemic.xyz"
      http:
        paths:
          - path: /yellow
            pathType: Prefix
            backend:
              service:
                name: yellow-service
                port:
                  number: 80
```

Greenアプリ用

```color-app-deployment-1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: yellow-app
  namespace: color-app-1
  labels:
    app: yellow-app
spec:
  selector:
    matchLabels:
      app: yellow-app
  replicas: 2
  template:
    metadata:
      labels:
        app: yellow-app
    spec:
      containers:
      - name: yellow-container
        image: 697333814333.dkr.ecr.ap-northeast-1.amazonaws.com/yellow:latest
        ports:
            - containerPort: 80
        resources:
          limits:
            memory: "100Mi"
            cpu: "200m"
```

```color-app-service-1.yaml
apiVersion: v1
kind: Service
metadata:
  namespace: color-app-1
  name: yellow-service
  labels:
    app: yellow-app
  annotations:
    alb.ingress.kubernetes.io/healthcheck-path: /yellow/index.html
spec:
  type: NodePort
  selector:
    app: yellow-app
  ports:
    - port: 80
      targetPort: 80
```

```color-app-ingress-2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: color-app-ingress
  namespace: color-app-2
  labels:
    app: color-app
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
    alb.ingress.kubernetes.io/healthcheck-port: traffic-port
    alb.ingress.kubernetes.io/healthcheck-interval-seconds: '15'
    alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '5'
    alb.ingress.kubernetes.io/success-codes: '200'
    alb.ingress.kubernetes.io/healthy-threshold-count: '2'
    alb.ingress.kubernetes.io/unhealthy-threshold-count: '2'
    alb.ingress.kubernetes.io/group.name: color-group
    external-dns.alpha.kubernetes.io/hostname: color-app-2.vamdemic.xyz
spec:
  rules:
    - host: "color-app-2.vamdemic.xyz"
      http:
        paths:
          - path: /green
            pathType: Prefix
            backend:
              service:
                name: green-service
                port:
                  number: 80
```

### デプロイ

Yellowアプリ

```
kubectl create namespace color-app-1
kubectl apply -f color-app-deployment-1.yaml
kubectl apply -f color-app-service-1.yaml
kubectl apply -f color-app-ingress-1.yaml
```

Greenアプリ

```
kubectl create namespace color-app-2
kubectl apply -f color-app-deployment-2.yaml
kubectl apply -f color-app-service-2.yaml
kubectl apply -f color-app-ingress-2.yaml
```

### テスト

Yellowアプリ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/fb7fd2ed-49fd-62c3-719c-9c89cd84367d.png)

Greenアプリ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293481/760e0c20-4f38-8f23-a8fd-3ff0e8263a95.png)

各NamespaceごとにIngressを作成したとしても、`alb.ingress.kubernetes.io/group.name`はnamespaceをまたぐものであるので共有ができる

## 注意点

- ingressの設定
    - 2.4.1で検証しました
    - externalDNSを設定してもいけます
        - その場合は、`host`を付ける必要がたぶんあって、つけない場合、メッシュ状に接続できてしまうのでその時点で想定されていないエンドポイントを公開してしまうことになると思うから

## 参考
https://aws.amazon.com/jp/blogs/news/how-to-expose-multiple-applications-on-amazon-eks-using-a-single-application-load-balancer/
https://developers.freee.co.jp/entry/2020/12/14/130003