我在 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 的问题,但我真的不知道为什么。
答案 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尝试重启。
仍然不确定为什么从未生成这些日志,但我通过任意更改部署清单中的 command
和 args
来发现这一点,而不是连续 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 传递。