侧边栏壁纸
博主头像
枕头下放双臭袜子博主等级

今我何功德,曾不事农桑

  • 累计撰写 166 篇文章
  • 累计创建 32 个标签
  • 累计收到 0 条评论
k8s

k8s pod启动时执行多行命令( influxdb示例 )

枕头下放双臭袜子
2022-03-08 / 0 评论 / 1 点赞 / 547 阅读 / 7,147 字 / 正在检测是否收录...

0、导

众所周知,pod本身可能会因为各种原因被重启,重启之后手动执行的修改就会被重置。比如,重启之后,手动使用influx命令修改的数据保留策略将会被重置为永久保存。

也就是说,如果我希望influxdb pod的数据保留策略一直是一个特定的时间(比如三个月),那就需要pod在每次启动前设置一次数据保留策略,也就是启动前执行特定命令。

1、操作尝试

1.1 报错permission denied

shell + configmap + command

首先将要执行的命令写成shell脚本的形式,将shell脚本作为configmap挂载到pod中,使用pod的command参数来执行该脚本

kind: ConfigMap
apiVersion: v1
metadata:
  name: influxdb-alter-retention-sh
  namespace: influxdb
  labels:
    app: influxdb
data:
  alter_retention_policy.sh:  |
    #!/bin/sh
    influx -username "telegraf" -password "XXXXXXXXX" -execute 'alter retention policy "autogen" on "telegraf" duration 90d replication 1 default'

---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: influxdb-deployment
  namespace: influxdb
  labels:
    app: influxdb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: influxdb
  template:
    metadata:
      labels:
        app: influxdb
    spec:
      containers:
        - name: influxdb
          image: influxdb:1.8.3
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 60000
            name: metrics
          - containerPort: 8086
            name: http-api
          - containerPort: 8088
            name: backup
          command: ["./conf/alter_retention_policy.sh"]
          volumeMounts:
          - name: influxdb-data-pvc
            mountPath: /var/lib/influxdb/
          - name: influxconf
            mountPath: /etc/influxdb/
          - name: influxdb-alter-retention-sh
            mountPath: /conf/alter_retention_policy.sh
            subPath: alter_retention_policy.sh
      volumes:
      - name: influxdb-data-pvc
        persistentVolumeClaim:
          claimName: influxdb-data-pvc
      - name: influxconf
        configMap:
          name: influxdb-config
      - name: influxdb-alter-retention-sh
        configMap:
          name: influxdb-alter-retention-sh

结果,apply资源清单之后报错permission denied,如下,看报错我们也知道原因是脚本没有执行权限导致报错。

Pasted Graphic.png
Error: failed to start container "influxdb": Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: "./conf/alter_retention_policy.sh": permission denied": unknown

所以需要给configmap加上defaultMode属性:

     volumes:
        configMap:
	# 因为我是用的是 1.15.2 版本的k8s,所以defaultMode的值范围是0-0777
          defaultMode: 0755
          name: influxdb-alter-retention-sh



└─╼ $kubectl explain deployments.spec.template.spec.volumes.configMap.defaultMode
KIND:     Deployment
VERSION:  extensions/v1beta1

FIELD:    defaultMode <integer>

DESCRIPTION:
     Optional: mode bits to use on created files by default. Must be a value
     between 0 and 0777. Defaults to 0644. Directories within the path are not
     affected by this setting. This might be in conflict with other options that
     affect the file mode, like fsGroup, and the result can be other mode bits
     set.
1.2 报错127.0.0.1:8086: connect: connection refused

待configmap脚本的属性修改完成之后,重新apply资源清单,得到报错Failed to connect to http://localhost:8086: Get http://localhost:8086/ping: dial tcp 127.0.0.1:8086: connect: connection refused Please check your connection settings and ensure 'influxd' is running.因为pod使用的是influxdb的镜像,influxd没找到,意思就是守护进程没启动喽。这是啥情况?

image.png

kubernetes.io文档说明,如果在配置文件中指定了容器启动时要执行的命令以及参数,那么容器镜像中自带的命令与参数将会被覆盖掉而不再执行。以上解释说明了报错的原因,因为通过资源清单的command字段指定了容器启动时要执行的命令,所以就覆盖掉了容器镜像本身的启动命令(也就是Dockerfile的CMD/ENTRYPOINT指令)。所以influxdb的守护进程没有被启动,自然也就没有地方去执行influx命令了。

image.png

image.png

1.3 解决问题

既然覆盖掉了Dockerfile的启动命令,我第一反应是定制化一个镜像,通过官方的Dockerfile修改CMD指令,将我们想要执行的命令在Dockerfile指定,这样不就不会产生谁覆盖谁的问题了嘛?

可是当我把这个问题推迟了一会儿之后我又发现,都是执行多条命令,我为啥还要再去定制化镜像一遍,何不直接通过k8s资源清单的command来执行被覆盖掉的Dockerfile启动命令呢?emmmm,好像是个解决办法!整!

有了解决,那就去扒一下influxdb的Dockerfile启动命令是啥吧。喏,地址在这里了。

FROM buildpack-deps:stretch-curl

RUN set -ex && \
    mkdir ~/.gnupg; \
    echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf; \
    for key in \
        05CE15085FC09D18E99EFB22684A14CF2582E0C5 ; \
    do \
        gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys "$key" ; \
    done

ENV INFLUXDB_VERSION 1.8.10
RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" && \
    case "${dpkgArch##*-}" in \
      amd64) ARCH='amd64';; \
      arm64) ARCH='arm64';; \
      armhf) ARCH='armhf';; \
      armel) ARCH='armel';; \
      *)     echo "Unsupported architecture: ${dpkgArch}"; exit 1;; \
    esac && \
    wget --no-verbose https://dl.influxdata.com/influxdb/releases/influxdb_${INFLUXDB_VERSION}_${ARCH}.deb.asc && \
    wget --no-verbose https://dl.influxdata.com/influxdb/releases/influxdb_${INFLUXDB_VERSION}_${ARCH}.deb && \
    gpg --batch --verify influxdb_${INFLUXDB_VERSION}_${ARCH}.deb.asc influxdb_${INFLUXDB_VERSION}_${ARCH}.deb && \
    dpkg -i influxdb_${INFLUXDB_VERSION}_${ARCH}.deb && \
    rm -f influxdb_${INFLUXDB_VERSION}_${ARCH}.deb*
COPY influxdb.conf /etc/influxdb/influxdb.conf

EXPOSE 8086

VOLUME /var/lib/influxdb

COPY entrypoint.sh /entrypoint.sh
COPY init-influxdb.sh /init-influxdb.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["influxd"]

从 Dockerfile 中可以看到,既有ENTRYPOINT又有CMD指令。Dockerfile的CMD和ENTRYPOINT什么区别呢?可以看下这篇文章就能弄懂。这里不再赘述它们的区别了,直接上结论:该 influxdb 的 Dockefile 同时使用了 CMD 和 ENTRYPOINT,此时ENTRYPOINT是 exec 模式,CMD 指定的内容则会被追加为 ENTRYPOINT 指定命令的参数。也就是说该镜像的启动命令是 /entrypoint.sh influxd。如果你再细看一下上边 Dockerfile 官方地址的目录结构,翻看一下entrypoint.sh的内容就知道它会检测influxd是否被作为了$1参数(shell语法,位置参数),如果跟了就会去执行另外一个脚本init-influxdb.sh

image.png

Tips:
"${@:2}" 也是shell的用法,如下示例

#!/bin/bash

echo ${@:2}
variable=${@:3}
echo $variable

-------------------------------
示例运行:
./ex.bash 1 2 3 4 5
2 3 4 5
3 4 5

所以,基于以上判断。那我们使用k8s的command参数覆盖Dockerfile参数的时候,需要执行该 /entrypoint.sh influxd命令,如下:

# 仅贴出来重要的部分
kind: ConfigMap
apiVersion: v1
metadata:
  name: influxdb-alter-retention-sh
  namespace: influxdb
  labels:
    app: influxdb
data:
  # -------------------------------- #
  # 重点一 是这里的shell脚本,执行influx命令修改数据保留策略
  # -------------------------------- #
  alter_retention_policy.sh:  |
    #!/bin/sh
    influx -username "telegraf" -password "xxxxxxxx" -execute 'alter retention policy "autogen" on "telegraf" duration 90d replication 1 default'
---
......
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: influxdb-deployment
  namespace: influxdb
  labels:
    app: influxdb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: influxdb
  template:
    metadata:
      labels:
        app: influxdb
    spec:
      containers:
        - name: influxdb
          image: influxdb:1.8.3
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 60000
            name: metrics
          - containerPort: 8086
            name: http-api
          - containerPort: 8088
            name: backup
          # -------------------------------- #
          # 重点二 是这里的 command 和 args 字段,需要将被覆盖的Dockerfile启动命令在这里执行
          # -------------------------------- #
          command: ["/bin/sh","-c"]
          args: ["/entrypoint.sh influxd; ./conf/alter_retention_policy.sh"]
          volumeMounts:
          - name: influxdb-data-pvc
            mountPath: /var/lib/influxdb/
          - name: influxconf
            mountPath: /etc/influxdb/
          - name: influxdb-alter-retention-sh
            mountPath: /conf/alter_retention_policy.sh
            subPath: alter_retention_policy.sh
      volumes:
      - name: influxdb-data-pvc
        persistentVolumeClaim:
          claimName: influxdb-data-pvc
      - name: influxconf
        configMap:
          name: influxdb-config
      - name: influxdb-alter-retention-sh
        configMap:
          defaultMode: 0755
          name: influxdb-alter-retention-sh

在上边的资源清单中,command 和 args 指令指定了两条pod启动命令,分别是/entrypoint.sh influxd./conf/alter_retention_policy.sh

使用 command 和 args 字段指定多条命令的exec模式写法如下:

    command: ["/bin/sh","-c"]
    args: ["command one; command two && command three"]
1.4 验证环节

经过 1.3 的解决问题环节,这里验证一下是否成功实现了influxdb pod启动时修改数据备份策略的目的

由图已经看到influxdb pod在启动时,数据备份策略已经被修改为了3个月的时间,成功实现
image.png

2、总结

通过本次实现 Influxdb Pod 启动修改默认数据保留策略为90天的过程,有这么几个小知识点和错误总结一下。

2.1 挂载到 Pod 内的文件如果需要可执行,需要修改 defaultMode 字段为相应值,比如我这里 1.15.2 版本的 0755。

image.png
参考1_kubernetes.io关于Secret的defaultMode

2.2 Dockerfile 的 ENTRYPOINT 和 CMD有exec模式和shell模式,exec模式写法是中括号[],比如 ENTRYPOINT ["COMMAND 1"],关于 Dockerfile 中 CMD 和 ENTRYPOINT 的复杂覆盖情况可见官方下图,一览各种情况

image.png
参考2_cnBlogs
参考3_Docker exec-form-entrypoint-example

2.3 如果在 Pod 配置文件()中指定了容器启动时要执行的命令以及参数,那么容器镜像中(Dockerfile CMD ENTRYPOINT)自带的命令与参数将会被覆盖掉而不再执行

参考4_kubernetes.io_为容器设置启动时要执行的命令和参数

2.4 influxdb的官方Dockerfile地址

2.5 shell位置参数回顾

0

评论