... views
Nginmesh 是 NGINX 的 Service Mesh 开源项目,用于 Istio 服务网格平台中的数据面代理。它旨在提供七层负载均衡和服务路由功能,与 Istio 集成作为 sidecar 部署,并将以“标准,可靠和安全的方式”使得服务间通信更容易。Nginmesh 在今年底已经连续发布了 0.2 和 0.3 版本,提供了服务发现,请求转发,路由规则,性能指标收集等功能。
备注:本文安装指南基于 Ubuntu 16.04,在 Centos 上某些安装步骤的命令可能需要稍作改动。
Kubernetes Cluster 包含 etcd, api server, scheduler,controller manager 等多个组件,组件之间的配置较为复杂,如果要手动去逐个安装及配置各个组件,需要了解 kubernetes,操作系统及网络等多方面的知识,对安装人员的能力要求较高。kubeadm 提供了一个简便,快速安装 Kubernetes Cluster 的方式,并且可以通过安装配置文件提供较高的灵活性,因此我们采用 kubeadm 安装 kubernetes cluster。
首先参照 kubeadm 的说明文档 在计划部署 kubernetes cluster 的每个节点上安装 docker,kubeadm, kubelet 和 kubectl。
安装 docker
apt-get update
apt-get install -y docker.io
使用 google 的源安装 kubelet kubeadm 和 kubectl
apt-get update && apt-get install -y apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
使用 kubeadmin 安装 kubernetes cluster
Nginmesh 使用 Kubernetes 的 Initializer 机制 来实现 sidecar 的自动注入。Initializer 目前是 kubernetes 的一个 Alpha feature,缺省是未启用的,需要 通过 api server 的参数 打开。因此我们先创建一个 kubeadm-conf 配置文件,用于配置 api server 的启动参数
apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
apiServerExtraArgs:
admission-control: Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ValidatingAdmissionWebhook,ResourceQuota,DefaultTolerationSeconds,MutatingAdmissionWebhook
runtime-config: admissionregistration.k8s.io/v1alpha1
使用 kubeadmin init 命令创建 kubernetes master 节点。 可以先试用–dry-run 参数验证一下配置文件。
kubeadm init --config kubeadm-conf --dry-run
如果一切正常,kubeadm 将提示:Finished dry-running successfully. Above are the resources that would be created.
下面再实际执行创建命令
kubeadm init --config kubeadm-conf
kubeadm 会花一点时间拉取 docker image,命令完成后,会提示如何将一个 work node 加入 cluster。如下所示:
kubeadm join --token fffbf6.13bcb3563428cf23 10.12.5.15:6443 --discovery-token-ca-cert-hash sha256:27ad08b4cd9f02e522334979deaf09e3fae80507afde63acf88892c8b72f143f
备注:目前 kubeadm 只能支持在一个节点上安装 master,支持高可用的安装将在后续版本实现。kubernetes 官方给出的 workaround 建议是定期备份 etcd 数据 kubeadm limitations 。
Kubeadm 并不会安装 Pod 需要的网络,因此需要手动安装一个 Pod 网络,这里采用的是 Calico
kubectl apply -f https://docs.projectcalico.org/v2.6/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml
使用 kubectl 命令检查 master 节点安装结果
ubuntu@kube-1:~$ kubectl get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12m
在每台工作节点上执行上述 kubeadm join 命令,即可把工作节点加入集群中。使用 kubectl 命令检查 cluster 中的节点情况。
ubuntu@kube-1:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kube-1 Ready master 21m v1.9.0
kube-2 Ready <none> 47s v1.9.0
参考 Nginmesh 文档 安装 Istio 控制面和 Bookinfo 该文档的步骤清晰明确,这里不再赘述。
需要注意的是,在 Niginmesh 文档中,建议通过 Ingress 的 External IP 访问 bookinfo 应用程序。但 Loadbalancer 只在支持的云环境中才会生效 ,并且还需要进行一定的配置。如我在 Openstack 环境中创建的 cluster,则需要参照 该文档 对 Openstack 进行配置后,Openstack 才能够支持 kubernetes 的 Loadbalancer service。如未进行配置,通过命令查看 Ingress External IP 一直显示为 pending 状态。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingress LoadBalancer 10.111.158.10 <pending> 80:32765/TCP,443:31969/TCP 11m
istio-mixer ClusterIP 10.107.135.31 <none> 9091/TCP,15004/TCP,9093/TCP,9094/TCP,9102/TCP,9125/UDP,42422/TCP 11m
istio-pilot ClusterIP 10.111.110.65 <none> 15003/TCP,443/TCP 11m
如不能配置云环境提供 Loadbalancer 特性, 我们可以直接使用集群中的一个节点 IP:Nodeport 访问 Bookinfo 应用程序。
http://10.12.5.31:32765/productpage
想要了解更多关于如何从集群外部进行访问的内容,可以参考 如何从外部访问 Kubernetes 集群中的应用?
使用 kubectl get pod reviews-v3-5fff595d9b-zsb2q -o yaml 命令查看 Bookinfo 应用的 reviews 服务的 Pod。
apiVersion: v1
kind: Pod
metadata:
annotations:
sidecar.istio.io/status: injected-version-0.2.12
creationTimestamp: 2018-01-02T02:33:36Z
generateName: reviews-v3-5fff595d9b-
labels:
app: reviews
pod-template-hash: "1999151856"
version: v3
name: reviews-v3-5fff595d9b-zsb2q
namespace: default
ownerReferences:
- apiVersion: extensions/v1beta1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: reviews-v3-5fff595d9b
uid: 5599688c-ef65-11e7-8be6-fa163e160c7d
resourceVersion: "3757"
selfLink: /api/v1/namespaces/default/pods/reviews-v3-5fff595d9b-zsb2q
uid: 559d8c6f-ef65-11e7-8be6-fa163e160c7d
spec:
containers:
- image: istio/examples-bookinfo-reviews-v3:0.2.3
imagePullPolicy: IfNotPresent
name: reviews
ports:
- containerPort: 9080
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-48vxx
readOnly: true
- args:
- proxy
- sidecar
- -v
- "2"
- --configPath
- /etc/istio/proxy
- --binaryPath
- /usr/local/bin/envoy
- --serviceCluster
- reviews
- --drainDuration
- 45s
- --parentShutdownDuration
- 1m0s
- --discoveryAddress
- istio-pilot.istio-system:15003
- --discoveryRefreshDelay
- 1s
- --zipkinAddress
- zipkin.istio-system:9411
- --connectTimeout
- 10s
- --statsdUdpAddress
- istio-mixer.istio-system:9125
- --proxyAdminPort
- "15000"
- --controlPlaneAuthPolicy
- NONE
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
image: nginmesh/proxy_debug:0.2.12
imagePullPolicy: Always
name: istio-proxy
resources: {}
securityContext:
privileged: true
readOnlyRootFilesystem: false
runAsUser: 1337
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/istio/proxy
name: istio-envoy
- mountPath: /etc/certs/
name: istio-certs
readOnly: true
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-48vxx
readOnly: true
dnsPolicy: ClusterFirst
initContainers:
- args:
- -p
- "15001"
- -u
- "1337"
image: nginmesh/proxy_init:0.2.12
imagePullPolicy: Always
name: istio-init
resources: {}
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-48vxx
readOnly: true
nodeName: kube-2
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- emptyDir:
medium: Memory
name: istio-envoy
- name: istio-certs
secret:
defaultMode: 420
optional: true
secretName: istio.default
- name: default-token-48vxx
secret:
defaultMode: 420
secretName: default-token-48vxx
status:
conditions:
- lastProbeTime: null
lastTransitionTime: 2018-01-02T02:33:54Z
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: 2018-01-02T02:36:06Z
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: 2018-01-02T02:33:36Z
status: "True"
type: PodScheduled
containerStatuses:
- containerID: docker://5d0c189b9dde8e14af4c8065ee5cf007508c0bb2b3c9535598d99dc49f531370
image: nginmesh/proxy_debug:0.2.12
imageID: docker-pullable://nginmesh/proxy_debug@sha256:6275934ea3a1ce5592e728717c4973ac704237b06b78966a1d50de3bc9319c71
lastState: {}
name: istio-proxy
ready: true
restartCount: 0
state:
running:
startedAt: 2018-01-02T02:36:05Z
- containerID: docker://aba3e114ac1aa87c75e969dcc1b0725696de78d3407c5341691d9db579429f28
image: istio/examples-bookinfo-reviews-v3:0.2.3
imageID: docker-pullable://istio/examples-bookinfo-reviews-v3@sha256:6e100e4805a8c10c47040ea7b66f10ad619c7e0068696032546ad3e35ad46570
lastState: {}
name: reviews
ready: true
restartCount: 0
state:
running:
startedAt: 2018-01-02T02:35:47Z
hostIP: 10.12.5.31
initContainerStatuses:
- containerID: docker://b55108625832a3205a265e8b45e5487df10276d5ae35af572ea4f30583933c1f
image: nginmesh/proxy_init:0.2.12
imageID: docker-pullable://nginmesh/proxy_init@sha256:f73b68839f6ac1596d6286ca498e4478b8fcfa834e4884418d23f9f625cbe5f5
lastState: {}
name: istio-init
ready: true
restartCount: 0
state:
terminated:
containerID: docker://b55108625832a3205a265e8b45e5487df10276d5ae35af572ea4f30583933c1f
exitCode: 0
finishedAt: 2018-01-02T02:33:53Z
reason: Completed
startedAt: 2018-01-02T02:33:53Z
phase: Running
podIP: 192.168.79.138
qosClass: BestEffort
startTime: 2018-01-02T02:33:39Z
该命令行输出的内容相当长,我们可以看到 Pod 中注入了一个 nginmesh/proxy_debug container,还增加了一个 initContainer nginmesh/proxy_init。这两个容器是通过 kubernetes initializer 自动注入到 pod 中的。这两个 container 分别有什么作用呢?让我们看一下 Nginmesh 源代码中的说明 :
proxy_debug, which comes with the agent and NGINX.
proxy_init, which is used for configuring iptables rules for transparently injecting an NGINX proxy from the proxy_debug image into an application pod.
proxy_debug 就是 sidecar 代理,proxy_init 则用于配置 iptable 规则,以将应用的流量导入到 sidecar 代理中。
查看 proxy_init 的 Dockerfile 文件,可以看到 proxy_init 其实是调用了 prepare_proxy.sh 这个脚本来创建 iptable 规则。
proxy_debug Dockerfile
FROM debian:stretch-slim
RUN apt-get update && apt-get install -y iptables
ADD prepare_proxy.sh /
ENTRYPOINT ["/prepare_proxy.sh"]
prepare_proxy.sh 节选
...omitted for brevity
# Create a new chain for redirecting inbound and outbound traffic to
# the common Envoy port.
iptables -t nat -N ISTIO_REDIRECT -m comment --comment "istio/redirect-common-chain"
iptables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-port ${ENVOY_PORT} -m comment --comment "istio/redirect-to-envoy-port"
# Redirect all inbound traffic to Envoy.
iptables -t nat -A PREROUTING -j ISTIO_REDIRECT -m comment --comment "istio/install-istio-prerouting"
# Create a new chain for selectively redirecting outbound packets to
# Envoy.
iptables -t nat -N ISTIO_OUTPUT -m comment --comment "istio/common-output-chain"
...omitted for brevity