注意:
- 本教程需要访问 Oracle Cloud。要注册免费账户,请参阅开始使用 Oracle Cloud Infrastructure 免费套餐。
- 它对 Oracle Cloud Infrastructure 身份证明、租户和区间使用示例值。完成实验室后,请使用特定于云环境的那些值替换这些值。
利用 SSH 隧道与 Oracle Cloud Infrastructure Kubernetes Engine 实现安全应用开发
简介
当我与 OKE 在 Ali Mukadam 的帮助下进行 SSH 隧道时,我称之为“魔法”。
他用以下信息回应了我:
“你叫它魔法,别人叫它科学。“我在哪里,他们是一样的。
最初的引用来自 Thor 电影:
“你的祖先称之为魔法,但你称之为科学。我来自一个地方,他们都是同一个地方。
这是什么魔法?
在现代应用开发中,保护本地资源与基于云的资源之间的连接至关重要,尤其是在使用 Oracle Cloud Infrastructure Kubernetes Engine(OCI Kubernetes Engine 或 OKE)时。SSH 隧道提供了一种简单而强大的方法来安全地连接到 OKE 集群,使开发人员能够在不向公共 Internet 公开资源的情况下管理和与资源交互。本教程将探讨如何使用 OKE 设置 SSH 隧道,以及开发人员如何将此方法集成到其工作流中以增强安全性和效率。从初始配置到优秀实践,我们将涵盖您在基于 OKE 的应用程序中有效利用 SSH 隧道所需的一切。
下图展示了 SSH 隧道连接两个不同应用程序的完整流量流。
目标
- 使用 OKE 通过 SSH 隧道进行安全应用开发。
任务 1:在 OKE 上部署 Kubernetes 集群(具有堡垒实例和操作员实例)
确保 OKE 上已部署 Kubernetes 集群。
-
要在 OKE 上部署 Kubernetes 集群,请使用以下方法之一:
-
使用 Oracle Cloud Infrastructure Kubernetes Engine 在 Terraform 上部署 Kubernetes 集群:使用 Terraform 在 OKE 上部署单个 Kubernetes 集群。
-
使用 Terraform 使用 OKE 在不同的 OCI 区域中部署多个 Kubernetes 集群,并使用 RPC 创建完整网格网络:使用 Terraform 在 OKE 上的多个区域部署多个 Kubernetes 集群。
-
任务 1:创建新的 Kubernetes 集群并验证组件:使用快速创建模式在 OKE 上部署 Kubernetes 集群。
-
任务 1:使用 OKE 部署 Kubernetes 集群:使用定制创建模式在 OKE 上部署 Kubernetes 集群。
在本教程中,我们将使用使用 Oracle Cloud Infrastructure Kubernetes Engine 部署带 Terraform 的 Kubernetes 集群作为 OKE 上的基本 Kubernetes 集群,以说明如何使用 SSH 隧道通过 localhost 访问在 OKE 上部署的基于容器的应用程序。
让我们快速查看 OCI OKE 环境以设置阶段。
-
-
虚拟云网络 (VCN)
登录到 OCI 控制台,导航到网络和虚拟云网络。
-
查看名为 oke 的 VCN。
-
单击 oke VCN。
-
-
子网
访问 VCN 详细信息页面。
- 单击子网。
- 查看已部署的子网。
-
网关
访问 VCN 详细信息页面。
- 单击 Internet Gateways 。
- 查看创建的 Internet 网关。
- 单击 NAT 网关。
- 查看创建的 NAT 网关。
- 单击服务网关。
- 查看创建的服务网关。
- 单击安全列表。
- 检查创建的安全性列表。
-
节点池
导航到 Developer Services 和 Container & Artifacts 。
- 单击 Kubernetes 集群 (OKE) 。
- 单击 oke 集群。
- 单击节点池。
- 查看节点池。
-
实例
导航到计算和实例。
- 单击实例。
- 查看 Kubernetes Worker 节点部署。
- 查看堡垒主机部署。
- 查看 Kubernetes Operator 部署。
-
下图显示了本教程剩余内容的完整概述。
-
下图展示了上图的简化视图。我们将在本教程的其余部分中使用此图。
任务 2:在 Kubernetes 集群上部署 NGINX Web 服务器
运营商不能直接从互联网访问,我们必须通过堡垒主机。
-
在本教程中,我们使用 Ali Mukadam 提供的 SSH 脚本,通过一个 SSH 命令连接到操作员。此处提供了此连接脚本和方法:任务 4:使用堡垒和运算符检查连接。在本教程的后面部分中您将需要此脚本,因此请确保使用它。
-
为 Kubernetes 操作员设置 SSH 会话。
-
使用
kubectl get nodes
命令查看活动的 Worker 节点。 -
查看所有活动的 Worker 节点。
-
-
要创建在容器内运行的示例 NGINX 应用程序,请创建一个名为
modified2_nginx_ext_lb.yaml
的 YAML 文件,该运算符包含以下代码。YAML 文件包含用于创建具有 3 个副本的 NGINX Web 服务器应用程序的代码,还将创建负载平衡器类型的服务。
modified2_nginx_ext_lb.yaml
:apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-nginx-svc labels: app: nginx annotations: oci.oraclecloud.com/load-balancer-type: "lb" service.beta.kubernetes.io/oci-load-balancer-internal: "true" service.beta.kubernetes.io/oci-load-balancer-subnet1: "ocid1.subnet.oc1.me-abudhabi-1.aaaaaaaaguwakvc6jxxxxxxxxxxxxxxxxxxxu7rixvdf5urvpxldhya" service.beta.kubernetes.io/oci-load-balancer-shape: "flexible" service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "50" service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "100" spec: type: LoadBalancer ports: - port: 80 selector: app: nginx
-
我们希望此应用可以在内部访问,并决定创建连接到专用负载平衡器子网的负载平衡器类型的服务。
要将类型为负载平衡器的服务分配给专用负载平衡器子网,您需要专用负载平衡器子网的子网 OCID,并且需要在注释部分中添加以下代码。
annotations: oci.oraclecloud.com/load-balancer-type: "lb" service.beta.kubernetes.io/oci-load-balancer-internal: "true" service.beta.kubernetes.io/oci-load-balancer-subnet1: "ocid1.subnet.oc1.me-abudhabi-1.aaaaaaaaguwakvcxxxxxxxxxxxxxxxxxxxxxxxxxxxxixvdf5urvpxldhya" service.beta.kubernetes.io/oci-load-balancer-shape: "flexible" service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "50" service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "100"
-
要获取专用负载平衡器子网的子网 OCID,请单击内部负载平衡器子网。
单击显示和复制以获取完整的专用负载平衡器子网 OCID。在 annotations 部分中使用此 OCID。
-
要部署 NGINX 应用程序和负载平衡器类型的服务,请运行以下命令:
-
在运算符上创建 YAML 文件。
nano modified2_nginx_ext_lb.yaml
-
使用类型为负载平衡器的服务部署 NGINX 应用程序。
kubectl apply -f modified2_nginx_ext_lb.yaml
验证 NGINX 应用程序是否已成功部署(未显示在映像中)。
kubectl get pods
-
验证负载平衡器类型的服务是否已成功部署。
kubectl get svc
-
请注意,已成功部署负载平衡器类型的服务。
-
-
当我们查看内部负载平衡器子网时,可以看到此子网的 CIDR 块为
10.0.2.0/27
。负载平衡器的新服务具有 IP 地址10.0.2.3
。 -
要在 OCI 控制台中验证负载平衡器对象,请导航到网络、负载平衡器,然后单击负载平衡器。
-
下图显示了我们迄今为止所做的部署。请注意,已添加负载平衡器。
测试新 Pod/应用程序
-
方法 1:从临时 pod
要测试新部署的 NGINX 应用程序是否正在使用负载平衡器类型的服务,我们可以使用临时 pod 进行内部连接测试。
有多种方法可以测试与应用程序的连接,一种方法是打开浏览器并测试您是否可以访问该网页。但是,当我们没有可用的浏览器时,我们可以通过部署临时 pod 来执行另一个快速测试。
要创建临时 pod 并将其用于连接测试,请参见 Task 3:Deploy a Sample Web Application and Service 。
-
运行以下命令:
-
获取内部负载平衡器服务的 IP 地址。
kubectl get svc
-
部署示例云池以测试 Web 应用程序连接。
kubectl run --rm -i -t --image=alpine test-$RANDOM -- sh
-
使用 wget 测试到 Web 服务器的连接。
wget -qO- http://<ip-of-internal-lb-service>
-
请注意 Web 服务器返回的 HTML 代码,确认 Web 服务器和使用内部负载平衡服务的连接正常工作。
-
-
运行以下命令以退出临时 pod。
exit
请注意,关闭命令行界面后,将立即删除 pod。
-
下图显示了我们迄今为止所做的部署。请注意,临时部署的云池正在连接到负载平衡器 IP 类型的服务以测试连接。
-
-
方法 2:从您的本地计算机
-
运行以下命令,通过本地笔记本电脑的负载平衡器类型服务测试与测试 NGINX 应用程序的连接。
iwhooge@iwhooge-mac ~ % wget -qO- <ip-of-internal-lb-service>
由于负载平衡器类型的服务具有内部 IP 地址并且只能在 Kubernetes 环境中访问,因此您会注意到,这当前不起作用。
-
运行以下命令以尝试使用具有定制端口
8080
的本地 IP 地址访问 NGINX 应用程序。iwhooge@iwhooge-mac ~ % wget -qO- 127.0.0.1:8080 iwhooge@iwhooge-mac ~ %
目前,这不起作用,但是在设置 SSH 隧道之后,我们将在本教程的后面使用相同的命令。
-
-
下图显示了我们迄今为止所做的部署。请注意,与本地 IP 地址的隧道连接不起作用。
任务 3:使用 Localhost 条目创建 SSH 配置脚本
为了让 SSH 隧道正常工作,我们需要在位于 /Users/iwhooge/.ssh
文件夹的 SSH 配置文件中添加以下条目。
-
运行
nano /Users/iwhooge/.ssh/config
命令以编辑配置文件。 -
在 Host operator47 部分中添加以下行。
LocalForward 8080 127.0.0.1:8080
-
SSH 配置文件的输出。
iwhooge@iwhooge-mac .ssh % pwd /Users/iwhooge/.ssh iwhooge@iwhooge-mac .ssh % more config Host bastion47 HostName 129.xxx.xxx.xxx user opc IdentityFile ~/.ssh/id_rsa UserKnownHostsFile /dev/null StrictHostKeyChecking=no TCPKeepAlive=yes ServerAliveInterval=50 Host operator47 HostName 10.0.0.11 user opc IdentityFile ~/.ssh/id_rsa ProxyJump bastion47 UserKnownHostsFile /dev/null StrictHostKeyChecking=no TCPKeepAlive=yes ServerAliveInterval=50 LocalForward 8080 127.0.0.1:8080 iwhooge@iwhooge-mac .ssh %
-
请注意,
LocalForward
命令已添加到 SSH 配置文件中。
任务 4:设置 SSH 隧道并使用 Localhost 连接到 NGINX Web 服务器
-
如果您使用 SSH 连接到操作员,请断开该会话的连接。
-
使用脚本再次重新连接到操作员。
iwhooge@iwhooge-mac ~ % ssh operator47
-
运行以下命令以获取内部负载平衡器服务的 IP 地址。
[opc@o-sqrtga ~]$ kubectl get svc
-
对操作员运行以下命令(SSH 窗口)以设置 SSH 隧道,并将转到 localhost
8080
的所有流量转发到类型为负载平衡器80
的服务。负载平衡器类型的服务随后将流量最终转发到 NGINX 应用程序。[opc@o-sqrtga ~]$ k port-forward svc/my-nginx-svc 8080:80
请注意 SSH 窗口上的 Forwarding 消息,本地主机端口
8080
将转发到端口80
。Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80
-
-
测试来自本地计算机的连接,并使用端口为
8080
的本地 IP 地址 (127.0.0.1
) 验证连接是否有效,并查看是否允许您连接到 OKE 环境内的 NGINX 应用程序。 -
打开新终端,然后运行以下命令测试连接。
iwhooge@iwhooge-mac ~ % wget -qO- 127.0.0.1:8080
-
请注意,您将在本地计算机的终端中获得以下输出,这意味着它正在运行。
iwhooge@iwhooge-mac ~ % wget -qO- 127.0.0.1:8080 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> iwhooge@iwhooge-mac ~ %
-
在操作员 SSH 窗口中,请注意输出已更改,新增了一行 Handling connection for 8080 。
-
使用 Web 浏览器的快速测试显示以下输出。
-
下图显示了我们迄今为止所做的部署。请注意,与本地 IP 地址的隧道连接正在工作。
任务 5:在 Kubernetes 集群上部署 MySQL Database 服务
我们可以通过 SSH 隧道访问 NGINX 应用程序,现在添加在 OKE 环境中运行的 MySQL 数据库服务。
-
要在 Kubernetes 环境中设置 MySQL 数据库服务,您需要创建:
- 用于密码保护的密钥。
- 数据库存储的持久性卷和持久性卷声明。
- 具有类型为负载平衡器的服务的 MYSQL 数据库服务。
-
运行以下命令以:
-
为 MySQL 数据库服务创建密码。
nano mysql-secret.yaml
在
mysql-secret.yaml
中复制以下 YAML 代码。apiVersion: v1 kind: Secret metadata: name: mysql-secret type: kubernetes.io/basic-auth stringData: password: Or@cle1
-
应用 YAML 代码。
kubectl apply -f mysql-secret.yaml
-
为 MySQL 数据库服务创建存储。
nano mysql-storage.yaml
在
mysql-storage.yaml
中复制以下 YAML 代码。apiVersion: v1 kind: PersistentVolume metadata: name: mysql-pv-volume labels: type: local spec: storageClassName: manual capacity: storage: 20Gi accessModes: - ReadWriteOnce hostPath: path: "/mnt/data" --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pv-claim spec: storageClassName: manual accessModes: - ReadWriteOnce resources: requests: storage: 20Gi
-
应用 YAML 代码。
kubectl apply -f mysql-storage.yaml
-
创建 MySQL 数据库服务和负载平衡器类型的服务。
nano mysql-deployment.yaml
在
mysql-deployment.yaml
中复制以下 YAML 代码。apiVersion: apps/v1 kind: Deployment metadata: name: mysql spec: selector: matchLabels: app: mysql strategy: type: Recreate template: metadata: labels: app: mysql spec: containers: - image: mysql:latest name: mysql env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password ports: - containerPort: 3306 name: mysql volumeMounts: - name: mysql-persistent-storage mountPath: /var/lib/mysql volumes: - name: mysql-persistent-storage persistentVolumeClaim: claimName: mysql-pv-claim --- apiVersion: v1 kind: Service metadata: name: my-mysql-svc labels: app: mysql annotations: oci.oraclecloud.com/load-balancer-type: "lb" service.beta.kubernetes.io/oci-load-balancer-internal: "true" service.beta.kubernetes.io/oci-load-balancer-subnet1: "ocid1.subnet.oc1.me-abudhabi-1.aaaaaaaaguwakvc6xxxxxxxxxxxxxxxxxxxxxx2rseu7rixvdf5urvpxldhya" service.beta.kubernetes.io/oci-load-balancer-shape: "flexible" service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "50" service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "100" spec: type: LoadBalancer ports: - port: 3306 selector: app: mysql
-
应用 YAML 代码。
kubectl apply -f mysql-deployment.yaml
-
验证是否已成功部署 MySQL 数据库服务。
kubectl get pod
-
请注意,MySQL 数据库服务已成功部署。
-
验证负载平衡器类型的服务是否已成功部署。
kubectl get svc
-
请注意,已成功部署负载平衡器类型的服务。
-
-
要在 OCI 控制台中验证负载平衡器对象,请导航到网络、负载平衡器并单击负载平衡器。
-
要访问 MySQL 数据库服务的终端控制台,可以使用
kubectl exec
命令和 localhost SSH 隧道命令。-
运行以下命令以从操作员访问终端控制台。
kubectl exec --stdin --tty mysql-74f8bf98c5-bl8vv -- /bin/bash
-
运行以下命令以访问 MySQL 数据库服务控制台。
mysql -p
-
输入您在
mysql-secret.yaml
文件中指定的密码,并注意到 MySQL 数据库服务的欢迎消息。 -
运行以下 SQL 查询以查看数据库服务内所有 MySQL 数据库的列表。
SHOW DATABASES;
现在,从 Kubernetes 环境中访问 MySQL 数据库服务管理控制台。
-
-
下图显示了我们迄今为止所做的部署。请注意,已部署具有类型为负载平衡器服务的 MySQL 服务。
任务 6:在 SSH 配置脚本内添加其他 Localhost 条目
在 SSH 配置脚本中添加其他 localhost 条目以访问新的 MySQL 数据库服务。
-
为了使 SSH 隧道适用于 MySQL 数据库服务,我们需要在位于
/Users/iwhooge/.ssh
文件夹的 SSH 配置文件中添加以下条目。 -
运行
nano /Users/iwhooge/.ssh/config
命令以编辑配置文件。 -
在 Host operator47 部分中添加以下行。
LocalForward 8306 127.0.0.1:8306
-
SSH 配置文件的输出。
Host bastion47 HostName 129.xxx.xxx.xxx user opc IdentityFile ~/.ssh/id_rsa UserKnownHostsFile /dev/null StrictHostKeyChecking=no TCPKeepAlive=yes ServerAliveInterval=50 Host operator47 HostName 10.0.0.11 user opc IdentityFile ~/.ssh/id_rsa ProxyJump bastion47 UserKnownHostsFile /dev/null StrictHostKeyChecking=no TCPKeepAlive=yes ServerAliveInterval=50 LocalForward 8080 127.0.0.1:8080 LocalForward 8306 127.0.0.1:8306
-
请注意,
LocalForward
命令已添加到 SSH 配置文件中。
任务 7:设置 SSH 隧道并使用 Localhost 连接到 MySQL Database
-
要测试从本地计算机到 MySQL 数据库服务的连接,您需要下载 MySQL Workbench 并将其安装在本地计算机上。
-
再次使用脚本打开操作员的新终端。让另一个终端打开。
iwhooge@iwhooge-mac ~ % ssh operator47
-
在操作员 SSH 窗口中运行以下命令以设置 SSH 隧道并将转到 localhost
8306
的所有流量转发到负载平衡器3306
类型的服务。负载平衡器类型的服务随后会将流量最终转发到 MySQL 数据库服务。[opc@o-sqrtga ~]$ k port-forward svc/my-mysql-svc 8306:3306
-
请注意 SSH 窗口上的 Forwarding 消息,本地主机端口
8306
将转发到端口3306
。Forwarding from 127.0.0.1:8306 -> 3306 Forwarding from [::1]:8306 -> 3306
-
-
安装 MySQL Workbench 应用程序并建立 SSH 会话和隧道,在本地计算机上打开 MySQL Workbench 应用程序。
-
单击 + 可添加新的 MySQL 连接。
-
在设置新连接中,输入以下信息。
- 连接名称:输入名称。
- 主机名:将 IP 地址输入为
127.0.0.1
(在通过隧道传送通信时为本地主机)。 - 端口:将端口输入为
8306
,这是用于 MySQL 数据库服务的本地隧道转发的端口。 - 单击测试连接。
- 口令:输入您在
mysql-secret.yaml
文件中指定的口令。 - 单击确定。
-
单击 Continue Anyway 以忽略连接警告。由于 MySQL Workbench 应用程序版本而部署的 MySQL 数据库服务版本可能不兼容,因此会发出此警告。
- 请注意成功的连接消息。
- 单击确定。
- 单击确定保存 MySQL 连接。
-
单击保存的 MySQL 连接以打开会话。
-
请注意 Please stand by... 消息。
-
单击 Continue Anyway 以忽略连接警告。
-
运行以下 SQL 查询以设置数据库服务内所有 MySQL 数据库的列表。
SHOW DATABASES;
-
单击闪电图标。
-
请注意 MySQL 数据库服务内所有 MySQL 数据库的输出。
-
-
在操作员 SSH 窗口中,注意到输出已更改,新增了一行 Handling connection for 8306 。
-
有多个条目,因为我们已建立多个连接,每个连接对应:
- 测试。
- 实际连接。
- SQL 查询。
- 我们之前所做的测试(附加)。
-
现在,我们可以向操作员打开多个 SSH 会话,同时为不同的应用程序运行多个隧道命令。请注意以下窗口。
- 包含用于 MySQL 数据库服务的隧道命令的 SSH 终端。
- 使用 MYSQL Workbench 应用程序从本地计算机到使用 localhost IP 地址
127.0.0.1
的 MySQL 数据库服务的连接。 - 包含 NGINX 应用程序隧道命令的 SSH 终端。
- 使用本地计算机中的 Safari Internet 浏览器连接到使用本地主机 IP 地址
127.0.0.1
的 NGINX 应用程序。
-
下图显示了我们迄今为止所做的部署。请注意,通过使用多个 SSH 会话和 SSH 隧道,与本地 IP 地址的隧道连接同时适用于 NGINX 应用程序和 MySQL 数据库服务。
任务 8:清除所有应用程序和服务
-
运行以下命令以清除已部署的 NGINX 应用程序和关联服务。
kubectl get pods kubectl delete service my-nginx-svc -n default kubectl get pods kubectl get svc kubectl delete deployment my-nginx --namespace default kubectl get svc
-
运行以下命令以清除已部署的 MySQL 数据库服务以及关联的服务、存储和密码。
kubectl delete deployment,svc mysql kubectl delete pvc mysql-pv-claim kubectl delete pv mysql-pv-volume kubectl delete secret mysql-secret
-
下图说明了到目前为止我们所做的部署,在此之前,您已重新拥有干净的环境并可以重新开始。
后续步骤
保护对 OKE 集群的访问是现代应用开发的关键步骤,SSH 隧道可提供强大而直接的解决方案。通过实施本教程中的步骤,开发人员可以保护其资源,简化其工作流,并保持对多个应用程序的敏感连接的控制。将 SSH 隧道集成到 OKE 设置中不仅可以增强安全性,还可以最大限度地降低向公共 Internet 公开资源带来的风险。借助这些实践,您可以自信地利用 OKE 集群,专注于构建可扩展、安全、高效的应用。
确认
- 作者 — Iwan Hoogendoorn(OCI 网络专家)
更多学习资源
浏览 docs.oracle.com/learn 上的其他实验室,或者访问 Oracle Learning YouTube 渠道上的更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 成为 Oracle Learning Explorer。
有关产品文档,请访问 Oracle 帮助中心。
Leverage SSH Tunneling with Oracle Cloud Infrastructure Kubernetes Engine for Secure Application Development
G21955-02
December 2024