【问题标题】:How to properly create sidecar container for creating SSH tunnel in kubernetes pod如何在 kubernetes pod 中正确创建用于创建 SSH 隧道的 sidecar 容器
【发布时间】:2021-09-29 00:25:57
【问题描述】:

我在 AWS 中有一个需要从 Kubernetes 连接的数据库,但该数据库中的安全设置阻止了这种情况。我的解决方案是从 Kubernetes pod 内通过 SSH 隧道连接到代理,并通过该隧道连接到 AWS 中的数据库。

但是,我不太确定如何在 Kubernetes 中真正实现这一点,因为 sidecar 容器会抛出“CrashLoopBackOff”错误。

我的 Dockerfile 很薄。它是一个 alpine 容器,除了复制一个处理隧道的 shell 脚本之外,实际上什么都不做。

Dockerfile

FROM alpine:3.14.0

COPY tunnel.sh /

RUN apk update && apk add curl \
    wget \
    nano \
    bash \
    ca-certificates \
    openssh-client

RUN chmod +x /tunnel.sh
RUN mkdir ~/.ssh

RUN ssh-keyscan -Ht ecdsa proxysql-sshtunnel.domain.com > ~/.ssh/known_hosts

CMD /bin/bash

tunnel.sh

#!/bin/bash
ssh -i /keys/sql_proxy.private -L 3306:10.0.0.229:6033 centos@proxysql-sshtunnel.domain.com -N

他们的 SSH 密钥从 Kubernetes 中的秘密卷挂载到 pod。我的部署如下所示:

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: accounts-deployment
  namespace: default
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: api-accounts
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    spec:
      containers:
      - image: gcr.io/xxxxxxxx/accounts:VERSION-2.0.6
        imagePullPolicy: Always
        name: accounts
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /tmp
          name: accounts-keys
          readOnly: true
        - mountPath: /var/www/html/var/spool
          name: mail-spool
      - image: gcr.io/xxxxxxxx/sql-proxy:latest
        imagePullPolicy: IfNotPresent
        name: sql-proxy
        args:
          - -c
          - /tunnel.sh
        command:
          - /bin/bash
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /keys
          name: keys-sql-proxy
          readOnly: true
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
      - name: accounts-keys
        secret:
          defaultMode: 420
          secretName: accounts-keys
      - name: spoonity-sql-proxy
        secret:
          defaultMode: 420
          secretName: spoonity-sql-proxy
      - emptyDir: {}
        name: mail-spool
status:

...
- image: gcr.io/xxxxxxxx/sql-proxy:latest
  imagePullPolicy: IfNotPresent
  name: sql-proxy
  args:
    - -c
    - /tunnel.sh
  command:
    - /bin/bash
  resources: {}
  terminationMessagePath: /dev/termination-log
  terminationMessagePolicy: File
  volumeMounts:
    - mountPath: /keys
      name: keys-sql-proxy
      readOnly: true
...

我从 Kubernetes 得到的唯一日志是:“/bin/bash: line 1: /tunnel.sh: No such file or directory

如果我尝试使用 docker run sql-proxy:latest /tunnel.sh 在 docker 中本地运行容器,则会收到另一个错误,抱怨密钥不存在(这正是我期望看到的)。

不确定这个问题出在哪里。

编辑:尝试在本地重建容器并手动包含密钥。我能够成功启动容器。所以看起来这绝对是 Kubernetes 的问题,但我真的不知道为什么。

【问题讨论】:

  • 从下面的答案“建议将 CMD 更改为您要运行的实际命令,而不是通过 kubernetes 传递它。”这是选项之一。其次是将命令/参数重写为this structure 的想法。我用你的选择进行了测试,它对我的​​情况不起作用。

标签: docker kubernetes ssh openssh


【解决方案1】:

这里的问题是您可能正在将文件复制到容器的/ 目录,但是当您启动容器时,shell 从~/ 目录启动。所以它找不到文件。

在 Dockerfile 的开头添加一个 WORKDIR 语句,这将确保您在启动容器时知道从哪里开始。

FROM alpine:3.14.0

WORKDIR /usr/src/app

COPY tunnel.sh .

RUN apk update && apk add curl \
    wget \
    nano \
    bash \
    ca-certificates \
    openssh-client

RUN chmod +x ./tunnel.sh

RUN mkdir ~/.ssh

RUN ssh-keyscan -Ht ecdsa proxysql-sshtunnel.domain.com > ~/.ssh/known_hosts

CMD /bin/bash

另外,建议将 CMD 更改为您要运行的实际命令,而不是通过 kubernetes 传递。

【讨论】:

  • 这并不能解决问题。我也不确定为什么会这样。该脚本位于根目录 (/)。它是从 / 在 Kubernetes 中调用的。将该绝对路径设为相对路径不应产生任何实质性影响。
【解决方案2】:

所以问题就在这里:

volumes:
      - name: accounts-keys
        secret:
          defaultMode: 420
          secretName: accounts-keys
      - name: spoonity-sql-proxy
        secret:
          defaultMode: 420 #<----------- this is wrong
          secretName: spoonity-sql-proxy

SSH 需要特定的密钥权限才能连接。 Kubernetes 使用基于十进制的文件权限,所以这里的正确值应该是 384,这将在 Linux 中以正确的权限 0600 挂载密钥。

由于权限错误,每次脚本尝试执行都会失败退出,触发Kubernetes尝试重启。

仍然不确定为什么从未生成这些日志,但我通过在我的部署清单中任意更改 commandargs 来发现这一点,而不是连续 ping localhost 以便容器至少可以启动:

...
 - image: gcr.io/xxxxxxxxx/sql-proxy:latest
   command: ["ping"]
   args: ["127.0.0.1"]
...

然后我连接到正在运行的 pod,并尝试手动运行 tunnel.sh 命令。现在我可以真正了解它失败的原因,我可以修复它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-28
    • 1970-01-01
    • 2022-01-05
    • 2021-10-01
    • 1970-01-01
    • 2012-08-05
    • 2021-11-02
    相关资源
    最近更新 更多