惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Privacy International News Feed
V
Vulnerabilities – Threatpost
The Last Watchdog
The Last Watchdog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
O
OpenAI News
T
Threat Research - Cisco Blogs
WordPress大学
WordPress大学
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Palo Alto Networks Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Help Net Security
P
Proofpoint News Feed
MyScale Blog
MyScale Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
T
The Blog of Author Tim Ferriss
H
Hackread – Cybersecurity News, Data Breaches, AI and More
S
Securelist
Vercel News
Vercel News
S
Security Affairs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
B
Blog RSS Feed
云风的 BLOG
云风的 BLOG
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Blog — PlanetScale
Blog — PlanetScale
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Last Week in AI
Last Week in AI
博客园_首页
Attack and Defense Labs
Attack and Defense Labs
G
Google Developers Blog
T
Tor Project blog
Project Zero
Project Zero
腾讯CDC
Schneier on Security
Schneier on Security
月光博客
月光博客
N
Netflix TechBlog - Medium
AWS News Blog
AWS News Blog
L
LINUX DO - 最新话题
P
Proofpoint News Feed
博客园 - 司徒正美
A
About on SuperTechFans
Latest news
Latest news
Scott Helme
Scott Helme
Hacker News: Ask HN
Hacker News: Ask HN
T
Threatpost
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
CERT Recently Published Vulnerability Notes
Google DeepMind News
Google DeepMind News
博客园 - 聂微东

博客园 - today4king

DOTNET 运行AES-GCM程序 ON MACOS(错误ALGORITHM ‘AESGCM’ IS NOT SUPPORTED ON THIS PLATFORM) MACBOOK M1 PRO 下运行.NET CORE(MAC下如何与X86_64兼容) Mac上使用SQL Server作为开发用数据库 EntityFramework Core CLI Tools 几点坑 VisualStudio Code Remote 调试方法(错误Containers Docker version 17.12.0 or later required.) AWS Kubernetes/k8s kubeamd 初始化后kube-controller-manager pod CrashLoopBackOff 错误启动不了 阿里云 NAS OSS 云盘价格对比 GB/小时 ❤️ 从125ms到11ms,记一次关键字检测过滤服务的优化 -python and Pythonnet 高效的的关键字查找和检测(哈希表和Trie前缀树和FastCheck)在实际使用中的性能 FastAPI 中的Async (并发和async/await) 阿里云vs华为云 的容器镜像服务swr使用体验 理工男对衣架的选择/衣柜收纳之衣架篇 Python中使用自定义类class作为海量数据结构时内存占用巨大的问题 关闭/开启 ubuntu 自动更新提示 blueImp/jQuery file upload 的正确用法(限制上传大小和文件类型) python3 crypto winrandom import error Flask-Babel 中文支持(zh-CN和zh-Hans-CN) Aapache status / apache2ctl status 总是403 为什么你还在用嵌入式的方式来使用mod_wsgi?
kubernetes/k8s pod下多容器的设计模式(ambassador 大使代理模式,adapter 适配模式,sidecar 边车模式, init containers初始化容器)
today4king · 2021-07-07 · via 博客园 - today4king

英文好的可以直接阅读原文:引用原文(英文):https://learnk8s.io/sidecar-containers-patterns

TL;TR:k8s patterns包含了云原生架构中各种的最佳实践,这里面绕不开用的最多的就是pod下多容器的pattern,也是k8s与swarm区别最大的地方。利用好这些pattern可以在不修改任何代码的情况下实现不同的行为比如TLS加固。

k8s把最小单位从容器上升到了pod是它设计的核心思想,这种设计带来了与原生docker容器无法比拟的优势,我们知道容器利用了linux下的各种命名空间用来隔离各种资源,但是pod作为多个容器的上一层,它可以利用命名空间是的这些容器共享某些资源从而达到亲缘性,比如共用网络、共用存储空间实现unionfile等。

示例: 一个安全的http服务

如何利用pod下多容器模式如何实现一个ElasticSearch服务的强化:

apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: elasticsearch
 spec:
   selector:
     matchLabels:
         es.test: elasticsearch
   template:
     metadata:
       labels:
         es.test: elasticsearch
     spec:
       containers:
       - name: elasticsearch
         image: elasticsearch:7.9.3
         env:
           - name: discovery.type
             value: single-node
         ports:
         - name:  http
           containerPort:  9200
 apiVersion: v1
 kind: Service
 metadata:
   name: elasticsearch
 spec:
   selector:
     es.test: elasticsearch
   ports:
 port: 9200
 targetPort: 9200 
kubectl run -it --rm --image=curlimages/curl curl \
   -- curl http://elasticsearch:9200
 {
   "name" : "elasticsearch-77d857c8cf-mk2dv",
   "cluster_name" : "docker-cluster",
   "cluster_uuid" : "z98oL-w-SLKJBhh5KVG4kg",
   "version" : {
     "number" : "7.9.3",
     "build_flavor" : "default",
     "build_type" : "docker",
     "build_hash" : "c4138e51121ef06a6404866cddc601906fe5c868",
     "build_date" : "2020-10-16T10:36:16.141335Z",
     "build_snapshot" : false,
     "lucene_version" : "8.6.2",
     "minimum_wire_compatibility_version" : "6.8.0",
     "minimum_index_compatibility_version" : "6.0.0-beta1"
   },
   "tagline" : "You Know, for Search"
 }

现在的访问是明文的,那么如何方便的使用多容器pod来实现TLS加固传输呢,如果你想到用ingress(通常用来路由外部流量到pod),这里从ingress到pod之间还是未加密的如下图:

The external traffic is routed to the Ingress and then to Pods.

那么满足zero-trust的办法就是给这个pod加入一个nginx代理tls加密流量如下图:

If you include a proxy container in the pod, you can terminate TLS in the Nginx pod.

增加一个nginx容器代理tls流量

apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: elasticsearch
 spec:
   selector:
     matchLabels:
       app.kubernetes.io/name: elasticsearch
   template:
     metadata:
       labels:
         app.kubernetes.io/name: elasticsearch
     spec:
       containers:
         - name: elasticsearch
           image: elasticsearch:7.9.3
           env:
             - name: discovery.type
               value: single-node
             - name: network.host
               value: 127.0.0.1
             - name: http.port
               value: '9201'
         - name: nginx-proxy
           image: nginx:1.19.5
           volumeMounts:
             - name: nginx-config
               mountPath: /etc/nginx/conf.d
               readOnly: true
             - name: certs
               mountPath: /certs
               readOnly: true
           ports:
             - name: https
               containerPort: 9200
       volumes:
         - name: nginx-config
           configMap:
             name: elasticsearch-nginx
         - name: certs
           secret:
             secretName: elasticsearch-tls
 apiVersion: v1
 kind: ConfigMap
 metadata:
   name: elasticsearch-nginx
 data:
   elasticsearch.conf: |
     server {
         listen 9200 ssl;
         server_name elasticsearch;
         ssl_certificate /certs/tls.crt;
         ssl_certificate_key /certs/tls.key;
     location / {         proxy_pass http://localhost:9201;     } }

前面的配置中我们利用用service可以让curl明文的访问es的接口,而这个配置中改为用nginx代理了9200,es只对localhost暴露9201,也就是从pod以外是访问不到es了。nginx在9200端口监听了https请求并转发给http的9200本地的端口给ES。

The request is proxies by Nginx on port 9220 and forwarded to port 9201 on Elastisearch

代理容器是最常用的一种Pattern

这种添加一个代理容器到一个pod的解决方式称之为:Ambassador Pattern

本文中所有模式都可以在google的研究文稿中找到详细的论述:https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/45406.pdf

添加基本的TLS还只是开始,除此之外还可以用这个模式做到以下几点:

  • 如果你希望集群上的流量都用tls证书加密,你可以在所有pod上加上一个nginx代理。或者你也可以更进一步使用mutual TLS来保证所有认证的请求已经被很好的加密,正如lstio 和linkerd在service meshes中做的。
  • 在OAuth认证中也可以使用nginx代理来保证所有请求是被jwt验证的。
  • 用在连接外部的数据库,比如一些不支持TLS或者旧版本的数据库时这也是很方便的方式。

暴露一个标准的接口用来度量

假设你已经熟悉如何使用 Prometheus来监控所有集群中的服务,但是你也正在使用一些原生并不支持 Prometheus度量的服务,比如Elasticsearch。

如何在不更改代码的情况下添加 Prometheus度量?

Adapter Pattern 适配模式

以ES为例,我们可以添加一个 exporter容器以Prometheus的格式暴露ES的度量。这非常简单,用一个开源的exporter for es 即可:

apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: elasticsearch
 spec:
   selector:
     matchLabels:
       app.kubernetes.io/name: elasticsearch
   template:
     metadata:
       labels:
         app.kubernetes.io/name: elasticsearch
     spec:
       containers:
         - name: elasticsearch
           image: elasticsearch:7.9.3
           env:
             - name: discovery.type
               value: single-node
           ports:
             - name: http
               containerPort: 9200
         - name: prometheus-exporter
           image: justwatch/elasticsearch_exporter:1.1.0
           args:
             - '--es.uri=http://localhost:9200'
           ports:
             - name: http-prometheus
               containerPort: 9114
 apiVersion: v1
 kind: Service
 metadata:
   name: elasticsearch
 spec:
   selector:
     app.kubernetes.io/name: elasticsearch
   ports:
     - name: http
       port: 9200
       targetPort: http
     - name: http-prometheus
       port: 9114
       targetPort: http-prometheus

通过这种方式可以更广泛的使用prometheus度量从而达到更好的应用与基础架构的分离。

日志跟踪 / Sidecar Pattern

边车模式,我一直把他想想成老式三轮摩托车的副座,它始终与摩托车主题保持一致并提供各种辅助功能,实现方式也是添加容器来曾强pod中应用。边车最经典的应用就是日志跟踪。

在容器化的环境中最标准的做法是标准输出日志到一个中心化的收集器中用于分析和管理。但是很多老的应用是将日志写入文件,而更改日志输出有时候是一件困难的事。

那么添加一个日志跟踪的边车就意味着你可能不必去更改日志代码。回到ElasticSearch这个例子,虽然它默认是标准输出把它写入文件有点做作,这里作为示例我们可以这样部署:

apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: elasticsearch
   labels:
     app.kubernetes.io/name: elasticsearch
 spec:
   selector:
     matchLabels:
       app.kubernetes.io/name: elasticsearch
   template:
     metadata:
       labels:
         app.kubernetes.io/name: elasticsearch
     spec:
       containers:
         - name: elasticsearch
           image: elasticsearch:7.9.3
           env:
             - name: discovery.type
               value: single-node
             - name: path.logs
               value: /var/log/elasticsearch
           volumeMounts:
             - name: logs
               mountPath: /var/log/elasticsearch
             - name: logging-config
               mountPath: /usr/share/elasticsearch/config/log4j2.properties
               subPath: log4j2.properties
               readOnly: true
           ports:
             - name: http
               containerPort: 9200
         - name: logs
           image: alpine:3.12
           command:
             - tail
             - -f
             - /logs/docker-cluster_server.json
           volumeMounts:
             - name: logs
               mountPath: /logs
               readOnly: true
       volumes:
         - name: logging-config
           configMap:
             name: elasticsearch-logging
         - name: logs
           emptyDir: {}

这里的logs容器就是sidecar的一个具体实现,现实中可以使用具体的日志收集器代替比如filebeat。当app持续写入数据时,边车中的日志收集程序会不断的以只读的形式收集日志,这里的logs边车就把写入文件的logs变为标准输出而不需要修改任何代码。

其他边车模式常用的场景

  • 实时的重启ConfigMaps而不需要重启pod
  • 从Hashcorp Vault注入秘钥
  • 添加一个本地的redis作为一个低延迟的内存缓存服务

在pod前的准备工作中使用Init Containers

k8s除了提供多容器外还提供了一种叫做初始化容器的功能,顾名思义它就是在pods 容器启动前工作的容器,我一般把它当做job这样的概念,一般场景中init containers这些容器在执行完后就不再运行了处于pause状态,这里特别要注意的是它的执行会严格按照编排的从上至下的顺序逐一初始化,这种顺序也是实现初始化工作不可缺少的。下面还是以ES为例子:

ES 文档中建议生产中设置vm.max_map_count这个sysctl属性。

这就带来了一个问题,这个属性只能在节点级别才可以被修改,容器级别是没有做到隔离。

所以在不修改k8s代码的情况下你不得不使用特权级别来运行es已达到修改的目的,而这也不是你所希望的,

因为他会带来很严重的安全问题

那么使用Init Containers就可以很好地解决这个问题,做法就是只在初始化容器中提权修改设置,那么后面的es只是普通容器就可以运行。如下:

apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: elasticsearch
 spec:
   selector:
     matchLabels:
       app.kubernetes.io/name: elasticsearch
   template:
     metadata:
       labels:
         app.kubernetes.io/name: elasticsearch
     spec:
       initContainers:
         - name: update-sysctl
           image: alpine:3.12
           command: ['/bin/sh']
           args:
             - -c
             - |
               sysctl -w vm.max_map_count=262144
           securityContext:
             privileged: true
       containers:
         - name: elasticsearch
           image: elasticsearch:7.9.3
           env:
             - name: discovery.type
               value: single-node
           ports:
             - name: http
               containerPort: 9200

除了上面这种常见的做法外初始化容器还可以这么用,当你HashicCorp Vault 来管理secrets而不是k8s secrets时,你可以在初始化容器中读取并放入一个emptyDir中。比如这样:

apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: myapp
   labels:
     app.kubernetes.io/name: myapp
 spec:
   selector:
     matchLabels:
       app.kubernetes.io/name: myapp
   template:
     metadata:
       labels:
         app.kubernetes.io/name: myapp
     spec:
       initContainers:
         - name: get-secret
           image: vault
           volumeMounts:
             - name: secrets
               mountPath: /secrets
           command: ['/bin/sh']
           args:
             - -c
             - |
               vault read secret/my-secret > /secrets/my-secret
       containers:
         - name: myapp
           image: myapp
           volumeMounts:
             - name: secrets
               mountPath: /secrets
       volumes:
         - name: secrets
           emptyDir: {}

更多的初始化容器应用场景

  • 你希望在运行app前跑数据库的迁移脚本
  • 从外部读取/拉取一个超大文件时可以避免容器臃肿

总结

这些pattern非常巧妙地用很小的代价非侵入的解决现实中常见的问题,这里要特别说明的是除了初始化容器会在运行后暂停不占用资源外,pods中增加的容器都是吃资源的,实际使用中我们不希望因为解决一个小问题反倒拖累整个pod,所以在边车这类容器组件的选择上要慎重,要足够的高效轻量,常见的像nginx、go写的大部分组件就是一个很好的选择,java写的就呵呵了。

如果希望挖掘更多多容器的设计细节可以查看官方文档:https://kubernetes.io/docs/concepts/workloads/pods/,还有google的容器设计论文:https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/45406.pdf