首页 > 解决方案 > 如何正确创建边车容器以在 kubernetes pod 中创建 SSH 隧道

问题描述

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

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

我的 Dockerfile 很薄。它是一个高山容器,除了复制一个处理隧道的 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

隧道.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。我的部署如下所示:

部署.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 在本地运行容器docker run sql-proxy:latest /tunnel.sh,则会收到一个不同的错误,抱怨密钥不存在(这正是我期望看到的)。

不知道这个问题出在哪里。

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

标签: dockerkubernetessshopenssh

解决方案


所以问题就在这里:

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尝试重启。

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

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

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


推荐阅读