Azure Kubernetes Configuration

Background

之前一直直接使用的虚拟机做为开发、测试甚至生产环境,使用的 Docker Compose 配置,毕竟自己不是运维,得过且过。

这次狠狠心再摸索一下 Kubernetes 做集群用于生产环境,记录一下踩坑的过程。

Azure Cloud

正好团队现在有比较多的资源在 Azure 国际版上,微软的文档也相对给力,所以直接使用了 Azure Kubernetes (AKS) 作为起点。

创建 Kubernetes 集群

1
$ ignore

使用 kubectl 连接到集群

  • 通过 az-cli 安装 kubectl
1
$ az aks install-cli
  • 通过 az-cli 连接集群
1
$ az aks get-credentials --resource-group $RESOURCE_GROUP --name $AKS_CLUSTER
  • 验证集群连接
1
$ kubectl get nodes

使用 Kubernetes Dashboard

AKS 里已经包含了 Dashboard,无需手动安装,但有个权限需要配置

如果 AKS 集群使用 RBAC,则必须先创建 ClusterRoleBinding,然后才能正确访问仪表板。

  • 创建 ClusterRoleBinding 权限绑定
1
$ kubectl create clusterrolebinding kubernetes-dashboard --clusterrole=cluster-admin --serviceaccount=kube-system:kubernetes-dashboard
  • 启动 Dashboard 并访问
1
$ az aks browse --resource-group $RESOURCE_GROUP --name $AKS_CLUSTER

这里需要注意的是,本地会启动一个代理指向集群的 Dashboard,默认是 127.0.0.1:8001 进行访问。

端口 8001 容易被其他服务占用,比如 v2rayx。

创建 Nginx 入口控制器

  • 获取 AKS 群集的资源组名称
1
$ az aks show --resource-group $RESOURCE_GROUP --name $AKS_CLUSTER --query nodeResourceGroup -o tsv

将会返回资源组名称 $RESOURCE_GROUP_NAME,格式一般为:MC_myResourceGroup_myAKSCluster_eastus

  • 创建静态公共 IP 地址

假设 $AKS_IP_NAME 值为 myAKSPublicIP

1
$ az network public-ip create --resource-group $RESOURCE_GROUP_NAME --name $AKS_IP_NAME --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv

成功后将返回 IP 地址 $IP

  • 创建命名空间 Namespace

假设 $NAMESPACE 值为 ingress-basic

1
$ kubectl create namespace $NAMESPACE
  • 创建 Nginx 控制器

此处使用 Helm 方式安装部署

当前创建两个 Nginx 的副本,可以通过 --set controller.replicaCount=2 修改

1
2
3
4
5
6
$ helm install nginx-ingress stable/nginx-ingress \
--namespace $NAMESPACE \
--set controller.replicaCount=2 \
--set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \
--set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux \
--set controller.service.loadBalancerIP="$IP"

成功后将会返回 Nginx 控制器的使用 YAML 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# An example Ingress that makes use of the controller:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: example
namespace: foo
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: exampleService
servicePort: 80
path: /
# This section is only required if TLS is to be enabled for the Ingress
tls:
- hosts:
- www.example.com
secretName: example-tls

# If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:

apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
type: kubernetes.io/tls

配置 DNS 名称

此步骤用于 HTTPS 证书正常工作,为入口控制器 IP 配置 FQDN

  • 获取 IP 地址的资源 ID

其中 $IP 为上文创建的静态 IP 地址

1
$ az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$ip')].[id]" --output tsv

成功后将返回 $IPID

  • 更新 IP 地址的 DNS 名称

假设 $DNSNAME 值为 aks-ingress

1
$ az network public-ip update --ids $IPID --dns-name $DNSNAME

安装证书管理器

此步骤用于 HTTPS 证书管理,适用于启用了 RBAC 的集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Install the CustomResourceDefinition resources separately
kubectl apply --validate=false -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.11/deploy/manifests/00-crds.yaml

# Create the namespace for cert-manager
kubectl create namespace cert-manager

# Label the cert-manager namespace to disable resource validation
kubectl label namespace cert-manager cert-manager.io/disable-validation=true

# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update your local Helm chart repository cache
helm repo update

# Install the cert-manager Helm chart
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--version v0.11.0

创建 CA 集群证书颁发者

  • 创建 cluster-issuer.yaml

此处直接使用 Let’s Encrypt 使用 prod 生产环境

若需使用 staging 环境,可以使用资源定义中的 letsencrypt-staginghttps://acme-staging-v02.api.letsencrypt.org/directory

letsencrypt-prod 和 https://acme-v02.api.letsencrypt.org/directory。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: ingress-basic
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
  • 部署 YAML
1
$ kubectl apply -f cluster-issuer.yaml

运行演示应用程序

1
helm install aks-helloworld azure-samples/aks-helloworld --namespace ingress-basic
1
2
3
4
helm install ingress-demo azure-samples/aks-helloworld \
--namespace ingress-basic \
--set title="AKS Ingress Demo" \
--set serviceName="ingress-demo"

创建入口路由

  • 创建 hello-world-ingress.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-world-ingress
namespace: ingress-basic
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
tls:
- hosts:
- demo-aks-ingress.10maker.com
secretName: tls-secret
rules:
- host: demo-aks-ingress.10maker.com
http:
paths:
- backend:
serviceName: aks-helloworld
servicePort: 80
path: /(.*)
- backend:
serviceName: ingress-demo
servicePort: 80
path: /hello-world-two(/|$)(.*)
  • 部署入口路由
1
$ kubectl apply -f hello-world-ingress.yaml