如何正确创建 sidecar 容器以在 kubernetes pod 中创建 SSH 隧道
How to properly create sidecar container for creating SSH tunnel in kubernetes pod
我在 AWS 中有一个数据库,我需要从 Kubernetes 连接到该数据库,但该数据库中的安全设置阻止了这一点。我的解决方案是通过 SSH 隧道从 Kubernetes pod 连接到代理,并通过它连接到 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
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 的问题,但我真的不确定为什么。
这里的问题是您可能正在将文件复制到容器的 /
目录,但是当您启动容器时,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 传递它。
所以问题出在这里:
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 本地主机,这样容器至少开始:
...
- image: gcr.io/xxxxxxxxx/sql-proxy:latest
command: ["ping"]
args: ["127.0.0.1"]
...
然后我连接到 now-运行ning pod,并尝试手动 运行 tunnel.sh 命令。现在我可以真正看到它失败的原因,我可以修复它。
我在 AWS 中有一个数据库,我需要从 Kubernetes 连接到该数据库,但该数据库中的安全设置阻止了这一点。我的解决方案是通过 SSH 隧道从 Kubernetes pod 连接到代理,并通过它连接到 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
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 的问题,但我真的不确定为什么。
这里的问题是您可能正在将文件复制到容器的 /
目录,但是当您启动容器时,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 传递它。
所以问题出在这里:
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 本地主机,这样容器至少开始:
...
- image: gcr.io/xxxxxxxxx/sql-proxy:latest
command: ["ping"]
args: ["127.0.0.1"]
...
然后我连接到 now-运行ning pod,并尝试手动 运行 tunnel.sh 命令。现在我可以真正看到它失败的原因,我可以修复它。