docker-compose的depends_on在kubernetes中对应什么

问题

docker-compose的yaml描述文件中对于依赖组件容器,我们常常会使用depends_on来申明,非常方便。比如下面这段:

service:
	worker: 
	  build: ./worker
	  image: xxxxxxxxxxxx
	  depends_on:
	    - redis
	    - postgres

那么到了kubernetes里面,容易习惯性的在脑袋中思考一个问题,我的依赖容器要怎么申明呢?或者更进一步说如何控制我容器的依赖启动顺序呢?

分析

确实,docker-compose作为"单点"编排工具的优势就是简单便捷啊,这一点毋庸置疑。Kubernetes作为功能超级强大的分布式容器编排工具,考虑的点和docker-compose不在同一个平面上。Kubernetes云原生的理念要求任何应用应该是“独立的”,应用自身是可以处理未连接或者重连接的情况,而不是交由Kuberntest集群层面来做,因为对于Kubernetes来说,Pod或者Container是随时会被调度/重起的,Kubernetes自身会检测所有的pod里的容器并确保它们活着并给他们贴上Healthy的标签,所以应该是尽量独立解耦的,不应该被绑定/关联太多才可以启动。

这段话你可以这么来理解,既然Pod你可以理解为“VM”,一台“virtual host”,那么你肯定不希望你的应用所在的“host”启动需要依赖于其它“host”的启动,而是你希望你的app所在的“host”——即Pod不论db状态如何,它都是可以“开机”的,app自身可以独立的去处理db的连接/重连问题。

方案

换句话说,在Kubernetes的体系中,并没有严格意义上和docker-compose的depends_on对等的"申明"语句。当然Kubernetes对于依赖容器也是可以透过一些特别的机制来实现类似的目的,不过可能需要修改app的逻辑。比如,我们可以在app的entrypoint或者initContainer当中去申明应用的启动逻辑,或者可以通过readiness探针来决定Kubernetes是否要启动Pod,同样也可以通过liveness探针来检测所依赖的服务是否健康。

initContainer

以initContainer为例,它是一个或多个先于应用容器启动的 Init 容器,每个都必须在下一个启动之前成功完成。默认的策略是若 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。下面例子是官方例子,定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 myservice 启动,第二个等待 mydb 启动。 一旦这两个 Init容器 都启动完成,Pod 将启动spec区域中的应用容器。

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]

注意initContainer里面的command,我们写了一段shell脚本一直循环运行,直到检测到myservicemydb都启动完毕才退出,并启动myapp容器。

注意:

  1. 在 Pod 上使用 activeDeadlineSeconds和在容器上使用 livenessProbe 可以避免 Init 容器一直重复失败。 activeDeadlineSeconds 时间包含了 Init 容器启动的时间;
  2. initContainers不支持readiness probes因为它们必须在Pod ready之前完成运行。

其中的myservice和mydb的定义如下:

kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
---
kind: Service
apiVersion: v1
metadata:
  name: mydb
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9377

再来看个ELK的例子,也是写了一段shell脚本并通过初始化容器的方式来实现的。

spec:
      initContainers:
      - name: wait-for-grafana
        image: darthcabs/tiny-tools:1
        args:
        - /bin/bash
        - -c
        - >
          set -x;
          while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' http://grafana:3000/login)" != "200" ]]; do 
            echo '.'
            sleep 15;
          done
      containers:
          .
          .
  (your other containers)
          .
          .

延伸

docker-compose depends_on与Helm dependencies区别

Helm的requirements.yaml中也申明了Chart包的依赖,如下所示,那么这个dependencies和docker-compose的depends_on的区别在哪呢?

dependencies:
  - name: mysql
    version: 3.2.1
    repository: http://another.example/charts

首先我们来看Helm dependencies怎么使用?

# 根据requirements.yaml配置,将依赖的应用包从仓库中拉取到charts目录,移除旧的
# 同时会生成requirements.lock
helm dependency update [flags] CHART

# 基于requirements.lock,重新构建charts中的应用
# 如果没有lock文档,类似update操作
helm dependency build [flags] CHART

# 展示应用依赖的所有子应用包
helm dependency list [flags] CHART

这里我们可以看到requirements.yaml是先转换为lock文件配置,然后Helm再基于lock文件去安装依赖服务,但是,这里需要明确的一点就是:Helm只是管理依赖并依据lock去创建pod,它并不会保证任何运行的顺序,以上面这个申明为例,Helm会创建2个pod,但它并不关心mysql pod可能要20s才完成启动而你的app容器只需要2s。

参考文章

  1. InitContainer官方文档
  2. How do we map depends_on in Kubernetes yamls ?
  3. What is the equivalent for depends_on in kubernetes
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
docker-compose 搭建的lamp+redis 代码 附上docker-compose # 标准配置文件应该包含 version、services、networks 三大部分, # 其最关键的就是 services 和 networks 两个部分,下面先来看 services 的书写规则 # 指定版本号 version: '2' services: # 在 services 标签下的第二级标签是 console,这个名字是用户自己自定义,它就是服务名称。 console: # 为自定义的容器指定一个名称,而不是使用默认的名称 container_name: console # 容器内置名称 hostname: console # 指明路径 build: # context 指定绝对路径或者相对路径 context: ./images/console # dockerfile 指定 Dockerfile 的文件名称 dockerfile: Dockerfile # volumes_from 从其它容器或者服务挂载数据卷, # 可选的参数是 :ro 或 :rw,前者表示容器只读,后者表示容器对数据卷是可读可写的(默认情况为可读可写的)。 volumes_from: - php # 挂载一个目录或者一个已存在的数据卷容器,可以直接使用 HOST:CONTAINER 这样的格式 # ,或者使用 HOST:CONTAINER:ro 这样的格式,后者对于容器来说,数据卷是只读的,这样可以有效保护宿主机的文件系统 volumes: # 使用绝对路径挂载数据卷 - /root/.ssh/:/root/.ssh/ # 类似于使用 docker run 的效果 我也不知道 不写因为console并不是直接启动导致镜像不会产生 tty: true # web,这个名字是用户自己自定义,它就是服务名称。 web: # 为自定义的容器指定一个名称,而不是使用默认的名称 container_name: web # 容器内置名称 hostname: web # 指明路径 build: # context 指定绝对路径或者相对路径 context: ./images/nginx # dockerfile 指定 Dockerfile 的文件名称 dockerfile: Dockerfile # 映射端口 ports: - '80:80' # 此选项解决了启动顺序的问题 这个的意思是必须在php启动以后才能启动 # 注意的是,默认情况下使用 docker-compose up web 这样的方式启动 web 服务时, # 也会启动 php 服务,因为在配置文件定义了依赖关系 depends_on: - php # volumes_from 从其它容器或者服务挂载数据卷, volumes_from: - php volumes: # 已经存在的命名的数据卷 - nginx-log:/var/log/nginx # 以 Compose 配置文件为心的相对路径作为数据卷挂载到容器 - ./images/nginx/sites-enabled:/etc/nginx/sites-enabled - ./images/nginx/cert:/etc/nginx/cert # 加入指定网络 networks: default: # 同一网络上的其他容器可以使用服务器名称或别名来连接到其他服务的容器 aliases: - web.sunchanghao.top - mid.sunchanghao.top - sevice.sunchanghao.top - admin.sunchanghao.top # php,这个名字是用户自己自定义,它就是服务名称。 php: # 为自定义的容器指定一个名称,而不是使用默认的名称 container_name: php # 容器内置名称 hostname: php # 服务除了可以基于指定的镜像,还可以基于一份 Dockerfile, # 在使用 up 启动之时执行构建任务,这个构建标签就是 build,它可以指定 Dockerfile # 所在文件夹的路径。Compose 将会利用它自动构建这个镜像,然后使用这个镜像启动服务容器 build: # context 选项可以是 Dockerfile 的文件路径,也可以是到链接到 git 仓库的 url # 当提供的值是相对路径时,它被解析为相对于撰写文件的路径,此目录也是发送到 Docker 守护进程的 context context: ./images/php # 使用此 dockerfile 文件来构建,必须指定构建路径 dockerfile: Dockerfile # 挂载一个目录或者一个已存在的数据卷容器, volumes: # 以 Compose 配置文件为心的相对路径作为数据卷挂载到容器。 - ./app:/mnt/app # db,这个名字是用户自己自定义,它就是服务名称。 db: # 为自定义的容器指定一个名称,而不是使用默认的名称 container_name: db # 容器内置名称 hostname: db # 从指定的镜像启动容器,可以是存储仓库、标签以及镜像 ID image: mysql:5.7 environment: MYSQL_USER: 'sch' MYSQL_PASS: '1111' MYSQL_ROOT_PASSWORD: 'root' volumes: - db:/var/lib/mysql ports: - '3306:3306' redis: # 为自定义的容器指定一个名称,而不是使用默认的名称 container_name: redis # 容器内置名称 hostname: redis # image 则是指定服务的镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试拉取这个镜像。 image: redis:3.2.7 # 设置端口号 ports: - '6379:6379' # 挂载一个目录或者一个已存在的数据卷容器 volumes: # 已经存在的命名的数据卷。 - redis:/data # node volumes: nginx-log: # 设置volume的驱动,默认是local. driver: local db: driver: local redis: driver: local

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值