k8sでcert-managerとexternal-dnsとIngressを組み合わせて速でサービス公開する
最近社内でもっぱらk8sを触っているなかで社内で雑にコンテナ立てるだけで https://example.com
とか公開できるようにした。
external-dns
まずは、名前解決ができるようにするのと、cert-managerを利用してLet’sEncryptでワイルドカード証明書を払い出すために、Route53を利用するためにexternal-dnsをたてた。
マニフェストは雑にこんな感じ。
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: example-system
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:v0.5.14
args:
- --source=service
- --source=ingress
- --domain-filter=<your domain>
- --provider=aws
- --policy=upsert-only
- --registry=txt
- --txt-owner-id=<your id>
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: external-dns
key: aws_access_key_id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: external-dns
key: aws_secret_access_key
Route53にアクセスするための権限が必要なので、ユーザーを払い出して、下記の権限を与えておいてください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "route53:ChangeResourceRecordSets",
"Resource": [
"arn:aws:route53:::hostedzone/*"
]
},
{
"Effect": "Allow",
"Action": "route53:ChangeResourceRecordSets",
"Resource": [
"arn:aws:route53:::hostedzone/*"
]
},
{
"Effect": "Allow",
"Action": "route53:GetChange",
"Resource": [
"arn:aws:route53:::change/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListHostedZonesByName",
"route53:ListResourceRecordSets"
],
"Resource": [
"*"
]
}
]
}
cert-manager
cert-managerはhelmを利用しました。こんな感じでシュッと入ります。
$ helm install \
--name cert-manager \
--namespace <your-namespace> \
stable/cert-manager
次にcert-managerが利用するCRDをデプロイします。これはGithubの最新パージョンを利用します。
$ kubectl -n <your-namespace> apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.6/deploy/manifests/00-crds.yaml
最後に、証明書の設定をCRDを利用して行います。
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: admin@example.com
# staging:https://acme-staging-v02.api.letsencrypt.org/directory
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-private-key
dns01:
providers:
- name: route53
route53:
accessKeyID: xxxxxxxxxxxxxxxxxxxxxxxxx
region: ap-northeast-1
secretAccessKeySecretRef:
name: external-dns
key: aws_secret_access_key
実際に証明書を発行するには下記のリソースをapplyしてください。
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: wildcard-example.com
spec:
acme:
config:
- dns01:
provider: route53
domains:
- '*.example.com'
commonName: '*.example.com'
issuerRef:
kind: ClusterIssuer
name: letsencrypt
secretName: cert-wildcard-example
発行状況は下記のコマンドで確認可能です。
$ kubectl describe cert wildcard-example.com
Ingressから利用する
Ingressのインストールは このあたりが参考になります。Ingressをデプロイしたら、あとはこのように利用できます。
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: hello-world-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: hello-world
spec:
containers:
- image: "strm/helloworld-http"
imagePullPolicy: Always
name: hello-world-container
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: hello-world-svc
annotations:
external-dns.alpha.kubernetes.io/hostname: example.com
spec:
type: ClusterIP
ports:
- port: 8080
protocol: TCP
targetPort: 80
selector:
app: hello-world
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-world-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.org/ssl-services: "hello-world-svc"
ingress.kubernetes.io/ssl-redirect: "false"
spec:
tls:
- hosts:
- example.com
secretName: cert-wildcard-example
rules:
- host: example.com
http:
paths:
- path: /
backend:
serviceName: hello-world-svc
servicePort: 8080
ペパボのように多くの商材がある会社では、このようにIngressを作っておくだけで簡単にサービスを公開できるので、社内システムなどすぐにレバレッジを効かせることができます。しかもhttpsな通信でセキュアだしお得。
最後に
最近はこういうことを全社でバーーーンとやれるように @r_takaishi とあれこれやっている。これからいよいよ既存サービスやOpenStack、AWSとk8sを組み合わせて移行したり、新しいものを作っていくフェーズなので誰か一緒にやりましょう。