我在 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 <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fb989e958f9488bb8b89948382888a97d68888938f8e95959e97d59f94969a9295d5989496" rel="noreferrer noopener nofollow">[email protected]</a> -N
它们的 SSH key 从 Kubernetes 中的 secret 卷安装到 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 本地运行容器,则会收到一个不同的错误,提示 key 不存在(即这正是我所期望看到的)。
不确定这个问题出在哪里。
编辑:尝试在本地重建容器并手动包含 key 。我能够成功启动容器。所以看起来这肯定是 Kubernetes 问题,但我真的不确定为什么。
最佳答案
所以问题就在这里:
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 需要特定的 key 权限才能连接。 Kubernetes 使用基于十进制的文件权限,因此此处的正确值应该是 384,这将在 Linux 中以正确的权限 0600 挂载 key 。
由于权限错误,每次脚本尝试执行都会失败并退出,触发 Kubernetes 尝试重启。
仍然不确定为什么这些日志从未生成,但我通过任意更改部署 list 中的 command
和 args
来发现这一点,而不是连续 ping localhost,这样容器至少会启动:
...
- image: gcr.io/xxxxxxxxx/sql-proxy:latest
command: ["ping"]
args: ["127.0.0.1"]
...
然后,我连接到正在运行的 pod,并尝试手动运行tunnel.sh 命令。现在我实际上可以了解它失败的原因,我可以修复它。
关于docker - 如何正确创建 sidecar 容器以在 kubernetes pod 中创建 SSH 隧道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68472696/