はじめに
静的サイトをサーバレスで公開したいときの選択肢の1つとしてS3のStatic Website Hostingがあります。
今回は独自ドメインでアクセスさせたいときやプライベート空間でアクセスさせたいときに使用できる例としてEKSを経由する方法を紹介します。
概観は次のようになります。ALB Ingress ControllerとNGINX Ingress Controllerを共存させる理由は後述します。
環境情報
macOS Mojave 10.14.6
EKS 1.16
Helm 2.14.3
手順
ここでは手順を説明していきます。EKSとHelm Tillerは既に構築済みであるものとします。
1. S3バケットの作成
今回はstatic-website-test01
という名前でS3バケットを作成します。
次にプロパティからStatic Website Hostingの設定を行います。
バケットポリシーはEKSと同一のVPCからのアクセスを許可するようにします。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::static-website-test01/*",
"Condition": {
"StringEquals": {
"aws:sourceVpc": "vpc-XXXXXXXX"
}
}
}
]
}
またS3バケットに次のファイルをアップロードしておきます。
<!DOCTYPE html>
<html>
<head>
<title>S3 Static Website</title>
</head>
<body>
<h1>S3 Static Website</h1>
</body>
</html>
2. VPC Endpointの作成
AWSコンソールから作成します。
VPCはEKSと同一のものを選択します。ポリシーは特に制限をかけません。
{
"Statement": [
{
"Action": "*",
"Effect": "Allow",
"Resource": "*",
"Principal": "*"
}
]
}
3. Ingress Controllerのデプロイ
ALB1つで対応するためにALB Ingress ControllerとNGINX Ingress Controllerを用意します。
その際kube2iamを用いてALB Ingress ControllerがALBを作成できるようにします。
デプロイはhelmfileを使用します。
repositories:
- name: stable
url: https://kubernetes-charts.storage.googleapis.com
- name: incubator
url: https://kubernetes-charts-incubator.storage.googleapis.com
releases:
# https://github.com/helm/charts/tree/master/stable/kube2iam
- name: kube2iam
namespace: kube-system
chart: stable/kube2iam
version: 2.0.1
wait: true
values:
- host:
iptables: true
interface: eni+
extraArgs:
auto-discover-base-arn: ""
rbac:
create: true
# https://github.com/helm/charts/tree/master/incubator/aws-alb-ingress-controller
- name: alb-ingress-controller
namespace: kube-system
chart: incubator/aws-alb-ingress-controller
version: 0.1.11
wait: true
values:
- clusterName: <CLUSTER-NAME>
autoDiscoverAwsRegion: true
autoDiscoverAwsVpcID: true
rbac:
serviceAccountAnnotations:
iam.amazonaws.com/role: arn:aws:iam::XXXXXXXXXX:role/alb-ingress-controller
# https://github.com/helm/charts/tree/master/stable/nginx-ingress
- name: nginx-ingress
namespace: kube-system
chart: stable/nginx-ingress
version: 1.39.0
wait: true
values:
- controller:
service:
type: NodePort
次のコマンドでデプロイします。
$ helmfile apply
4. Ingress, Serviceのデプロイ
ALBを作成するためにALB Ingress Controllerに読み込ませるためのIngressをデプロイします。
spec.rules[].host
を定義せずに、全リクエストをNGINX Ingress Controllerに飛ばすようにします。
また、annotationsのalb.ingress.kubernetes.io/scheme
の値はpublicかprivateかで変わってくることに注意しましょう。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
kubernetes.io/ingress.class: alb
name: alb-ingress
namespace: kube-system
spec:
rules:
- http:
paths:
- backend:
serviceName: nginx-ingress-controller
servicePort: 80
NGINX Ingress Controllerに読み込ませるIngressを作成します。
ポイントはannotationsにnginx.ingress.kubernetes.io/upstream-vhost
を付けてホストヘッダを変えることです。
これは、S3バケット毎にIngressリソースが必要になることを示しています。
このことを考慮しALB Ingress ControllerとNGINX Ingress Controllerを組み合わせて、ALBやCLBの複数作成を防いでいます。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/upstream-vhost: static-website-test01.s3-website-ap-northeast-1.amazonaws.com
name: nginx-ingress
namespace: default
spec:
rules:
- host: s3.sample.com
http:
paths:
- backend:
serviceName: s3-static-website
servicePort: 80
ExternalName ServiceでS3バケットのエンドポイントを指定します。
apiVersion: v1
kind: Service
metadata:
name: s3-static-website
namespace: default
spec:
type: ExternalName
externalName: static-website-test01.s3-website-ap-northeast-1.amazonaws.com
次のコマンドでデプロイします。
$ kubectl apply -f alb-ingress.yaml
$ kubectl apply -f nginx-ingress.yaml
$ kubectl apply -f externalname-service.yaml
あとは、Route53などでnginx-ingress.yaml
で定義したs3.sample.com
の名前解決を行いALBに転送されるよう設定します。
確認
試しにブラウザからS3バケットのエンドポイントに直接アクセスしようとしても、公開されていないので拒否されることが確認できます。
次にIngressで定義した独自ドメインでアクセスします。
index.html
が表示されることが分かります。
まとめ
EKSを経由してS3 Static Websiteにアクセスできることを確認しました。
S3バケットを公開しない方法の1つとして使用できる構成かと思います。
セキュリティを上げるためにNGINX Ingress ControllerにBasic認証を付けるのも良いかもしれません。