人的一生是短的,但如果卑劣地过这一生,就太长了。——莎士比亚
文前预览
1. 什么是sidecar模式
2. sidecar的注入和流量劫持
4. k8s实现sidecar自动注入
1. 什么是sidecar模式
上篇文章我们已经了解了服务网格大致做什么,同时我们也提到了sidecar和iptables,那么这边文章着重聊下sidecar模式和iptables技术。
sidecar模式通俗地讲就是将控制和逻辑分离,控制负责服务注册,服务发现以及服务限流等功能,逻辑主要是负责业务功能模块的实现,如上图那样,应用服务(车主)你只管开好你的车,打仗的事情就交给sidecar(副手)就好。这与分布式微服务架构完美契合,真正的实现了控制和逻辑的分离与解耦。
2. sidecar注入和流量劫持
k8s中每个pod在初始化应用服务之前,需要先初始化一个init容器,这个init容器负责运行包含一些应用服务镜像中不存在的实用工具或安装脚本。
2.1 sidecar注入
一个Pod中可以指定多个Init容器,如果指定了多个,那么Init容器将会按顺序依次运行。只有当前面的Init容器必须运行成功后,才可以运行下一个Init容器。当所有的Init容器运行完成后,Kubernetes 才初始化Pod和运行应用容器。
注入sidecar:命令行展示如下
istioctl kube-inject -f yaml/istio-bookinfo/bookinfo.yaml //bookinfo.yaml参考:https://github.com/rootsongjc/kubernetes-vagrant-centos-cluster/blob/master/yaml/istio-bookinfo/bookinfo.yaml
我们看下注入sidecar之后bookinfo的service和deploment yaml配置
service:
apiVersion: v1 kind: Service metadata: name: productpage labels: app: productpage spec: ports: - port: 9080 name: http selector: app: productpage
deploment
apiVersion: extensions/v1beta1 kind: Deployment metadata: creationTimestamp: null name: productpage-v1 spec: replicas: 1 strategy: {} template: metadata: annotations: sidecar.istio.io/status: '{"version":"fde14299e2ae804b95be08e0f2d171d466f47983391c00519bbf01392d9ad6bb","initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["istio-envoy","istio-certs"],"imagePullSecrets":null}' creationTimestamp: null labels: app: productpage version: v1 spec: containers: - image: istio/examples-bookinfo-productpage-v1:1.8.0 imagePullPolicy: IfNotPresent name: productpage ports: - containerPort: 9080 resources: {} - args: - proxy - sidecar - --configPath - /etc/istio/proxy - --binaryPath - /usr/local/bin/envoy - --serviceCluster - productpage - --drainDuration - 45s - --parentShutdownDuration - 1m0s - --discoveryAddress - istio-pilot.istio-system:15007 - --discoveryRefreshDelay - 1s - --zipkinAddress - zipkin.istio-system:9411 - --connectTimeout - 10s - --statsdUdpAddress - istio-statsd-prom-bridge.istio-system:9125 - --proxyAdminPort - "15000" - --controlPlaneAuthPolicy - NONE env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: INSTANCE_IP valueFrom: fieldRef: fieldPath: status.podIP - name: ISTIO_META_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: ISTIO_META_INTERCEPTION_MODE value: REDIRECT image: jimmysong/istio-release-proxyv2:1.0.0 imagePullPolicy: IfNotPresent name: istio-proxy resources: requests: cpu: 10m securityContext: privileged: false readOnlyRootFilesystem: true runAsUser: 1337 volumeMounts: - mountPath: /etc/istio/proxy name: istio-envoy - mountPath: /etc/certs/ name: istio-certs readOnly: true initContainers: //init容器的iptables参数 - args: - -p - "15001" - -u - "1337" - -m - REDIRECT - -i - '*' - -x - "" - -b - 9080, - -d - "" image: jimmysong/istio-release-proxy_init:1.0.0 imagePullPolicy: IfNotPresent name: istio-init resources: {} securityContext: capabilities: add: - NET_ADMIN privileged: true volumes: - emptyDir: medium: Memory name: istio-envoy - name: istio-certs secret: optional: true secretName: istio.default status: {}
我们着重看下deployment配置,Istio给应用Pod注入的配置主要包括:
- Init容器istio-init:用于给sidecar容器做初始化,设置iptables端口转发
- sidecar容器istio-proxy:运行Envoy代理(后面说这个玩意儿是啥 暂且忽略)
我们一起看下init容器的dockfile:
FROM ubuntu:xenial RUN apt-get update && apt-get install -y \ iproute2 \ iptables \ && rm -rf /var/lib/apt/lists/* ADD istio-iptables.sh /usr/local/bin/ ENTRYPOINT ["/usr/local/bin/istio-iptables.sh"]
们看到istio-init容器的入口是/usr/local/bin/istio-iptables.sh
脚本。这个脚本会将deploment中的initContainer中的参数组装成iptables的参数进行调用,iptables可以根据NAT技术实现流量转发和控制。
组装完整的iptables命令如下:
$ /usr/local/bin/istio-iptables.sh -p 15001 -u 1337 -m REDIRECT -i '*' -x "" -b 9080 -d ""
这条启动命令的作用是:
- 将应用容器的所有流量都转发到Envoy的15001端口。
- 使用istio-proxy用户身份运行, UID为1337,即Envoy所处的用户空间,这也是istio-proxy容器默认使用的用户。
- 使用默认的REDIRECT模式来重定向流量。
- 将所有出站流量都重定向到Envoy代理。
- 将所有访问9080端口(即应用容器bookinfo的端口的流量重定向到Envoy代理。
因为init容器初始化完毕后就会自动终止,因为我们无法登陆到容器中查看iptables信息,但是init容器初始化结果会保留到应用容器和Sidecar容器中,我们可以登录Sidecar中查看iptables的nat规则列表。
该容器存在的意义就是让Envoy代理可以拦截所有的进出Pod的流量,即将入站流量重定向到Sidecar,再拦截应用容器的出站流量经过Sidecar处理后再出站。
2.2 iptables技术
流量劫持是通过iptables技术来实现的,它是Linux内核中的防火墙软件netfilter的管理工具,位于用户空间,同时也是netfilter的一部分。Netfilter位于内核空间,不仅有网络地址转换的功能,也具备数据包内容修改、以及数据包过滤等防火墙功能。
具体大家下来自行去查看研究,这不是本文重点。
3. k8s实现sidecar自动注入
所谓自动sidecar注入就是将生成Pod配置从应用yml文件期间转移到mutable webhook中,这样当k8s api server启动的时候默认会走一些准入控制器,这样我们就会把sidecar自动注入到pod中,让其伴在应用服务容器旁边提供控制服务。
4. 参考
- bookinfo.yaml https://github.com/rootsongjc/kubernetes-vagrant-centos-cluster/blob/master/yaml/istio-bookinfo/bookinfo.yaml
- init容器 https://jimmysong.io/kubernetes-handbook/concepts/init-containers.html
- iptables技术 https://www.zsythink.net/archives/1517
- mutable webhook https://jimmysong.io/kubernetes-handbook/concepts/admission-controller.html
5 关注公众号
微信公众号:堆栈future