如何正确创建 sidecar 容器以在 kubernetes pod 中创建 SSH 隧道

时间:2021-07-21 15:51:03

标签: docker kubernetes ssh openssh

我在 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 的问题,但我真的不知道为什么。

2 个答案:

答案 0 :(得分:1)

问题就在这里:

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 命令。现在我可以真正了解它失败的原因,我可以修复它。

答案 1 :(得分:0)

这里的问题是您可能正在将文件复制到容器的 / 目录,但是当您启动容器时,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 传递。