【问题标题】:How to set multiple commands in one yaml file with Kubernetes?如何使用 Kubernetes 在一个 yaml 文件中设置多个命令?
【发布时间】:2016-02-26 12:18:17
【问题描述】:

在这个官方文档中,它可以在 yaml 配置文件中运行命令:

https://kubernetes.io/docs/tasks/configure-pod-container/

apiVersion: v1
kind: Pod
metadata:
  name: hello-world
spec:  # specification of the pod’s contents
  restartPolicy: Never
  containers:
  - name: hello
    image: "ubuntu:14.04"
    env:
    - name: MESSAGE
      value: "hello world"
    command: ["/bin/sh","-c"]
    args: ["/bin/echo \"${MESSAGE}\""]

如果我想运行多个命令,怎么办?

【问题讨论】:

    标签: yaml kubernetes


    【解决方案1】:
    command: ["/bin/sh","-c"]
    args: ["command one; command two && command three"]
    

    解释:command ["/bin/sh", "-c"] 表示“运行一个 shell,并执行以下指令”。然后将 args 作为命令传递给 shell。在 shell 脚本中,分号分隔命令,如果第一个成功,&& 有条件地运行以下命令。在上面的示例中,它始终运行command one,后跟command two,并且只有在command two 成功时才运行command three

    替代方案:在许多情况下,您要运行的某些命令可能正在设置要运行的最终命令。在这种情况下,构建自己的Dockerfile 是可行的方法。尤其是RUN 指令。

    【讨论】:

    • 是的,非常有效,但是,我认为还有很好的用例可以扩展 command,因为它会覆盖 Dockerfile 的 Entrypoint ;)
    • 对如何使用容器生命周期执行此操作有任何想法吗?它没有参数
    • @aclokay 您可以将参数指定为附加命令字符串。 Container 中 command 和 args 之间的分离只是为了更容易覆盖参数。它们在功能上是等效的。
    • -c 在这里做什么?
    • @Abdul 表示运行作为参数提供的脚本,而不是启动交互式 shell 或从文件加载脚本。
    【解决方案2】:

    我的偏好是多行 args,这是最简单和最容易阅读的。另外,脚本可以在不影响镜像的情况下更改,只需要重新启动 pod。例如,对于 mysql 转储,容器规范可能是这样的:

    containers:
      - name: mysqldump
        image: mysql
        command: ["/bin/sh", "-c"]
        args:
          - echo starting;
            ls -la /backups;
            mysqldump --host=... -r /backups/file.sql db_name;
            ls -la /backups;
            echo done;
        volumeMounts:
          - ...
    

    这样做的原因是 yaml 实际上将“-”之后的所有行连接成一个,并且 sh 运行一个长字符串“echo starting; ls...; echo done;”。

    【讨论】:

    • 很好,但是当您请求使用 kubectl 进行编辑时,它将再次出现在一行中。 :)
    • @sekrett 哦,不! :(
    • 这很好用——关键是每一行的分号。当命令很多并且与上述解决方案多行时,这是一个特别好的解决方案。让 git diff 变得轻而易举
    • 这就是我要找的。在此解决方案中使用环境变量作为参数效果很好。
    • +1 漂亮,加上多行命令完美运行:command: ['/bin/bash', '-c']args:- exec &> /path/to/redirected/program.output;`python /program.py``--key1=val1``--key2=val2` ` --key3=val3`
    【解决方案3】:

    如果您愿意使用 Volume 和 ConfigMap,可以将 mount ConfigMap data 作为脚本,然后运行该脚本:

    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: my-configmap
    data:
      entrypoint.sh: |-
        #!/bin/bash
        echo "Do this"
    
        echo "Do that"
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      containers:
      - name: my-container
        image: "ubuntu:14.04"
        command:
        - /bin/entrypoint.sh
        volumeMounts:
        - name: configmap-volume
          mountPath: /bin/entrypoint.sh
          readOnly: true
          subPath: entrypoint.sh
      volumes:
      - name: configmap-volume
        configMap:
          defaultMode: 0700
          name: my-configmap
    

    这会稍微清理您的 pod 规范,并允许编写更复杂的脚本。

    $ kubectl logs my-pod
    Do this
    Do that
    

    【讨论】:

    • 非常酷,但我认为将脚本内联更简单,只需使用多行语法。我在一个单独的答案中展示了这一点。
    • 当我需要传递双引号时怎么办。例如想象这个命令: printf '%s @%s\n' "$(echo 'user')" "$(echo 'host')"
    • 这是最灵活的解决方案
    【解决方案4】:

    如果您想避免使用;&& 将所有命令连接成一个命令,您还可以使用heredoc 获得真正的多行脚本:

    command: 
     - sh
     - "-c"
     - |
       /bin/bash <<'EOF'
    
       # Normal script content possible here
       echo "Hello world"
       ls -l
       exit 123
    
       EOF
    

    这对于运行现有的 bash 脚本很方便,但缺点是需要一个内部和一个外壳实例来设置 heredoc。

    【讨论】:

    • 我们如何设置heredoc?
    • 通过在运行时获得$SHELL 输出:\bin\ash
    • 感谢 sn-p。
    【解决方案5】:

    我不确定这个问题是否仍然有效,但由于我在上述答案中没有找到解决方案,我决定把它写下来。

    我使用以下方法:

    readinessProbe:
      exec:
        command:
        - sh
        - -c
        - |
          command1
          command2 && command3
    

    我知道我的示例与 readinessProbe、livenessProbe 等有关,但怀疑容器命令也是如此。这提供了灵活性,因为它反映了在 Bash 中编写的标准脚本。

    【讨论】:

      【解决方案6】:

      恕我直言,最好的选择是使用 YAML 的原生 block scalars。特别是在这种情况下,折叠样式块。

      通过调用sh -c,您可以将参数作为命令传递给您的容器,但如果您想用换行符优雅地分隔它们,您需要使用折叠样式块,以便 YAML将知道将换行符转换为空格,从而有效地连接命令。

      一个完整的工作示例:

      apiVersion: v1
      kind: Pod
      metadata:
        name: myapp
        labels:
          app: myapp
      spec:
        containers:
        - name: busy
          image: busybox:1.28
          command: ["/bin/sh", "-c"]
          args:
          - >
            command_1 &&
            command_2 &&
            ... 
            command_n
      

      【讨论】:

      • 但是如果你去编辑部署yaml,它将在一行中,再次无法读取
      • kubectl edit 之类的方式编辑实时资源是一种反模式,也是一个坏主意。您的运行配置应始终与您的清单上所写的内容相匹配。这就是声明式配置和版本控制系统的用途。
      【解决方案7】:

      这是我成功的运行

      apiVersion: v1
      kind: Pod
      metadata:
        labels:
          run: busybox
        name: busybox
      spec:
        containers:
        - command:
          - /bin/sh
          - -c
          - |
            echo "running below scripts"
            i=0; 
            while true; 
            do 
              echo "$i: $(date)"; 
              i=$((i+1)); 
              sleep 1; 
            done
          name: busybox
          image: busybox
      

      【讨论】:

        【解决方案8】:

        这是另一种方法,使用输出日志记录。

        apiVersion: v1
        kind: Pod
        metadata:
          labels:
            type: test
          name: nginx
        spec:
          containers:
          - image: nginx
            name: nginx
            volumeMounts:
              - name: log-vol
                mountPath: /var/mylog
            command:
                - /bin/sh
                - -c
                - >
                    i=0;
                    while [ $i -lt 100 ];
                    do
                     echo "hello $i";
                     echo "$i :  $(date)" >> /var/mylog/1.log;
                     echo "$(date)" >> /var/mylog/2.log;
                     i=$((i+1));
                     sleep 1;
                    done
        
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          volumes:
            - name: log-vol
              emptyDir: {}
        

        【讨论】:

        • 感谢您的示例
        【解决方案9】:

        这是运行多行命令的另一种方式。

        api版本:批处理/v1 种类:工作 元数据: 名称:多线 规格: 模板: 规格: 容器: - 命令: - /bin/bash --exc - | 设置 +x echo "在脚本下运行" 如果 [[ -f "if-condition.sh" ]];然后 echo "成功则运行" 别的 echo "如果失败则运行" 菲 名称:ubuntu 图片:Ubuntu 重启策略:从不 退避限制:1

        【讨论】:

          【解决方案10】:

          只是为了带来另一种可能的选择,可以使用秘密,因为它们作为卷呈现给 pod:

          秘籍:

          apiVersion: v1
          kind: Secret 
          metadata:
            name: secret-script
          type: Opaque
          data:
            script_text: <<your script in b64>>
          

          Yaml 提取物:

          ....
          containers:
              - name: container-name
                image: image-name
                command: ["/bin/bash", "/your_script.sh"]
                volumeMounts:
                  - name: vsecret-script
                    mountPath: /your_script.sh
                    subPath: script_text
          ....
            volumes:
              - name: vsecret-script
                secret:
                  secretName: secret-script
          

          我知道很多人会争辩说这不是必须使用秘密的目的,但它是一种选择。

          【讨论】:

            猜你喜欢
            • 2012-12-05
            • 2018-06-26
            • 1970-01-01
            • 2021-06-14
            • 2018-12-18
            • 2020-02-02
            • 2019-11-08
            相关资源
            最近更新 更多