在 VPC 中的虚拟服务器实例上安装软件
本教程可能会发生成本。 使用 成本估算器 根据您的预计使用量生成成本估算。
本教程将指导您供应 IBM Cloud® Virtual Private Cloud (VPC) 基础架构,以及使用 Terraform 和 Ansible 等基础架构即代码 (IaC) 工具在虚拟服务器实例 (VSI)上安装软件。
在 介绍完教程架构 之后,您将为教程 准备环境 并查看 IBM Cloud 中 软件安装的基础知识。 此时,您可以决定评估所有技术,或者直接跳转到特定的独立部分,例如 Terraform 或 Ansible。
目标
- 了解 IBM 提供的操作系统软件。
- 利用更新操作系统软件并安装新软件的手动步骤。
- 了解如何使用 IBM Cloud CLI、Terraform 和 Ansible 来自动供应资源和执行软件安装。
在本教程中,您将部署另一个教程 ( Virtual Private Cloud 中的公共前端和专用后端) 中引入的配置。 您将供应可通过公用因特网访问的前端服务器,用于与无因特网连接的后端服务器进行对话。
该配置还包括 一个堡垒主机,作为跳转服务器,允许安全连接到没有公共IP地址的实例:

在供应资源时,您还将在虚拟服务器实例上部署应用程序。 在云中部署应用程序时,软件可以来自不同的来源:
- 本地工作站的文件系统 - 使用 Terraform 等工具来创建必需的基础架构,或使用 Ansible、
ssh
和scp
在虚拟服务器实例上安装和配置软件; - IBM 镜像 - 用于更新操作系统或安装支持的包;
- 因特网或内部网软件存储库。

您将探索如何使用这些不同的来源。
准备工作
创建 VPC SSH 密钥
供应虚拟服务器实例时,将向这些实例中注入 SSH 密钥,以便稍后可以连接到服务器。
- 如果本地机器上没有 SSH 密钥,请参阅 这些指示信息 以创建 VPC 的密钥。 缺省情况下,在
$HOME/.ssh/id_rsa
处找到专用密钥。 - 在 VPC 控制台中的计算 / SSH 密钥下,添加 SSH 密钥。 请确保在要在本教程中创建其他资源的同一资源组中创建密钥。
设置环境变量
本教程随附的样本代码演示了在 VPC 环境中供应资源以及安装或更新软件的不同选项。
样本代码将全程指导您使用 shell、terraform
和 ansible
在终端上完成示例步骤。 在稍后步骤中将安装这些工具。 要使脚本能够正常运作,您需要定义一组环境变量。
-
克隆教程 源代码存储库:
git clone https://github.com/IBM-Cloud/vpc-tutorials.git
-
定义名为
CHECKOUT_DIR
的变量,以指向源代码目录:cd vpc-tutorials export CHECKOUT_DIR=$PWD
-
切换到教程目录:
cd $CHECKOUT_DIR/vpc-app-deploy
-
复制配置文件:
cp export.template export
-
编辑
export
文件,并设置环境变量值:-
TF_VAR_ibmcloud_api_key
是 IBM Cloud API 密钥。 您可以在控制台中创建一个密钥。 -
TF_VAR_ssh_key_name
是先前部分中标识的 VPC SSH 公用密钥的名称。 这是将装入到虚拟服务实例,以通过工作站上的专用密钥提供安全 SSH 访问的公用密钥。 使用 CLI 来验证它是否存在:ibmcloud is keys
-
TF_VAR_resource_group_name
是将在其中创建资源的资源组。 请参阅创建和管理资源组。 -
TF_VAR_region
是将在其中创建资源的区域。 此命令将显示区域:ibmcloud is regions
-
TF_VAR_zone
是将在其中创建资源的区域。 此命令将显示区域:ibmcloud is zones
-
TF_VAR_ssh_agent
指示使用受口令保护的 SSH 密钥。 通过取消注释该变量来启用该变量。 然后,使用ssh-add ~/.ssh/id_rsa
将 SSH 密钥添加到认证代理程序。
-
-
将变量装入到环境中:
source export
确保在后续各部分中始终使用相同的终端窗口,否则如果使用新窗口,需设置环境变量。
export
中的环境变量 为Terraform格式 (注意TF_VAR_
前缀),以方便使用。 后续各部分中将使用这些变量。
软件安装基础知识
通过基本映像供应虚拟服务器实例
供应虚拟服务器实例时,请从 IBM 提供的一组预定义的操作系统映像中选择基本映像。 使用 ibmcloud is images
来查找可用映像的列表。
IBM 有内部镜像来支持 IBM 映像。 这些镜像将在 IBM 提供的映像中包含软件的新版本以及与分发版关联的可选包。 镜像是可用于 IBM Cloud VPC的 服务端点 的一部分。 读取镜像没有任何流入成本。
请考虑通过这些镜像更新已供应实例可用的版本列表,以及升级已安装的软件。
使用 cloud-init 初始化和定制云实例
在配置虚拟服务器实例时,您可以指定一个要在服务器初始化期间执行的 云初始化脚本。 cloud-init 是一个多分发包,用于处理云实例的早期初始化。 cloud-init 定义了一组文件格式,用于对云实例初始化进行编码。
在 IBM Cloud 中,供应服务器时,会在 user-data
参数中提供 cloud-init 文件内容。 请参阅 用户数据格式,了解可接受的用户数据内容。 如果需要调试脚本执行,那么
cloud-init 会在虚拟服务器实例上的 /var/log/cloud-init-output.log
中记录初始化脚本的输出。
本教程使用名为 install.sh 作为初始化脚本:
#!/bin/bash
set -x
apt-get update
apt-get install -y nginx
indexhtml=/var/www/html/index.html
# Demonstrate the availability of internet repositories. If www.python.org is availble then other software internet software like
# npm, pip, docker, ... if isolated only the software from the ibm mirrors can be accessed
if curl -o /tmp/x -m 3 https://www.python.org/downloads/release/python-373/; then
echo INTERNET > $indexhtml
else
echo ISOLATED > $indexhtml
fi
在此脚本中,使用操作系统提供的软件安装工具来升级已安装的软件,并安装 nginx
和其他包,这些操作演示了即使隔离的实例也可以访问 IBM 提供的镜像。 对于 Ubuntu,将使用 apt-get
命令来访问镜像。
访问 www.python.org 的 curl
命令演示了如何尝试从因特网访问软件以及可能的软件安装操作。
根据主机是否具有因特网连接,此脚本会修改 index.html
提供的 nginx
页面。
从文件系统上传并在实例上执行
内部部署系统或 CI/CD 管道的文件系统上可能提供有数据和软件,这些数据和软件需要上传到虚拟服务器实例,然后加以执行。
在此类情况下,可以使用与服务器的 SSH 连接通过 scp
上传文件,然后通过 ssh
在服务器上执行脚本。 假定您在内部部署系统和云之间建立了连接,如 VPN,那么这些脚本还可以通过因特网或在内部部署系统中检索软件安装程序。
教程代码包含一个名为 uploaded.sh
,该脚本将从您的工作站上传到虚拟服务器实例(手动或通过Terraform和 Ansible 等自动化工具)。
在后面的部分中,您将使用脚本 test_provision.bash 确认服务器配置成功,能够(或不能)访问互联网,以及 uploaded.sh
脚本是否正确执行。
使用 IBM Cloud CLI 和 shell 脚本
IBM Cloud CLI 提供了用于与您可以在 IBM Cloud 中创建的所有资源进行交互的命令。 本节说明如何使用这些命令,但您不会创建任何资源。 建议使用 Terraform 来部署完整解决方案。
准备工作
通过执行以下步骤,安装命令行 (CLI) 工具。
供应虚拟服务器实例并安装软件
CLI 具有 适用于所有 VPC 相关功能的插件,包括计算和网络资源。
-
在使用 VPC 资源之前,请设置当前资源组和区域:
ibmcloud target -g $TF_VAR_resource_group_name -r $TF_VAR_region
-
要供应虚拟服务器实例,请运行
ibmcloud is instance-create
CLI 命令。 在shared/install.sh
是用于初始化前端和后端服务器的云初始化文件。 您可以将脚本与--user-data
参数一起传递,如下所示:ibmcloud is instance-create ... --user-data @shared/install.sh
-
部署了前端和后端 VSI 并处于维护方式后,您可以向前端服务器 (例如,前端服务器) 发送脚本,然后运行脚本以从因特网安装软件。 向前端服务器发送脚本:
scp -F ../scripts/ssh.notstrict.config -o ProxyJump=root@$BASTION_IP_ADDRESS shared/uploaded.sh root@$FRONT_NIC_IP:/uploaded.sh
然后执行此脚本:
ssh -F ../scripts/ssh.notstrict.config -o ProxyJump=root@$BASTION_IP_ADDRESS root@$FRONT_NIC_IP sh /uploaded.sh
服务器的ssh服务需要几分钟才能初始化,而
cloud-init
脚本还需要几分钟才能完成。uploaded.sh
脚本将等待初始化完成,然后再退出。
使用 Terraform 供应基础架构
Terraform 使您能够安全、可预测地创建、更改和改进基础设施。 Terraform 是一个开放式源代码工具,用于将 API 编码为声明式配置文件,这些文件可以在团队成员之间共享,视为代码,进行编辑、复查和版本化。
准备工作
遵循指示信息在工作站上 安装 Terraform 和 IBM Cloud Terraform 的提供程序插件。
供应单个虚拟服务器实例
在部署更复杂的体系结构之前,为了验证 Terraform 提供程序安装,请使用浮动 IP 来部署单个虚拟服务器实例,然后通过 SSH 访问此服务器。
查看terraform脚本文件。main.tf 文件,查看terraform脚本。 它利用的是先前定义的环境变量。
-
对于此示例,请切换到 Terraform 脚本文件夹:
cd $CHECKOUT_DIR/vpc-app-deploy/tfinstance
-
初始化 Terraform:
terraform init
-
应用 Terraform 套餐:
terraform apply
此脚本会创建 VPC、VSI 并启用 SSH 访问。
-
查看套餐生成的输出:
terraform output
-
您可以复制并粘贴先前命令的输出,也可以如下所示使用
terraform output
通过 SSH 登录到 VSI。$(terraform output -raw sshcommand)
应用了 Terraform 套餐后,如果您希望在其他脚本中复用资源属性,那么使用 Terraform 中的输出会非常方便。
-
除去由 Terraform 创建的资源:
terraform destroy
供应子网和虚拟服务器实例
Terraform 文件集位于 vpc-app-deploy/tf
文件夹 vpc-tutorials
存储库实现了虚拟私有云教程中的公共前端和私有后端的架构。
脚本 vpc-app-deploy/tf/main.tf 包含资源的定义。 它导入了与其他教程共享的 Terraform 模块:
module vpc_pub_priv {
source = "../../vpc-public-app-private-backend/tfmodule"
basename = "${local.BASENAME}"
ssh_key_name = "${var.ssh_key_name}"
zone = "${var.zone}"
backend_pgw = false
profile = "${var.profile}"
image_name = "${var.image_name}"
resource_group_name = "${var.resource_group_name}"
maintenance = "${var.maintenance}"
frontend_user_data = "${file("../shared/install.sh")}"
backend_user_data = "${file("../shared/install.sh")}"
}
在此定义中:
- backend_pgw 控制后端服务器是否有权访问公用因特网。 公共网关可以连接到后端子网。 前端分配有一个浮动 IP,用于提供针对因特网的公共 IP 和网关。 这将允许打开因特网访问以供软件安装。 后端无权访问因特网。
- frontend_user_data 和 backend_user_data 指向 cloud-init 初始化脚本。
对于 Terraform,所有资源都可以具有关联的供应者。 null_resource
供应者不会供应云资源,但可以用于将文件复制到服务器实例。 脚本中使用此结构复制 uploaded.sh 文件,然后执行它,如下所示。 为了连接到服务器,Terraform 支持 使用本教程中配置的堡垒主机:
resource "null_resource" "copy_from_on_prem" {
connection {
type = "ssh"
user = "root"
host = "${module.vpc_pub_priv.frontend_network_interface_address}"
private_key = "${file("~/.ssh/id_rsa")}"
bastion_user = "root"
bastion_host = "${local.bastion_ip}"
bastion_private_key = "${file("~/.ssh/id_rsa")}"
}
provisioner "file" {
source = "../shared/${local.uploaded}"
destination = "/${local.uploaded}"
}
provisioner "remote-exec" {
inline = [
"bash -x /${local.uploaded}",
]
}
}
要供应资源,请执行以下操作:
- 切换到 Terraform 脚本文件夹:
cd $CHECKOUT_DIR/vpc-app-deploy/tf
- 初始化 Terraform:
terraform init
- 应用 Terraform 套餐:
terraform apply
- 查看套餐生成的输出:
terraform output
测试虚拟服务器的配置
既然 Terraform 已经部署了资源,现在可以验证这些资源是否已正确供应。
- 验证前端虚拟服务器实例是否可访问,并具有对因特网的出站访问权:
命令输出应该如下:../test_provision.bash $(terraform output -raw FRONT_IP_ADDRESS) INTERNET hi
success: httpd default file was correctly replaced with the following contents: INTERNET success: provision of file from on premises worked and was replaced with the following contents: hi
- 验证后端是否可通过防御主机访问,以及是否无权访问因特网:
命令输出应该如下:../test_provision.bash $(terraform output -raw BACK_NIC_IP) ISOLATED hi "ssh -F ../../scripts/ssh.notstrict.config root@$(terraform output -raw FRONT_NIC_IP) -o ProxyJump=root@$(terraform output -raw BASTION_IP_ADDRESS)"
success: httpd default file was correctly replaced with the following contents: ISOLATED success: provision of file from on premises worked and was replaced with the following contents: hi
除去资源
- 除去由 Terraform 创建的资源:
terraform destroy
使用 Ansible 安装软件
Ansible 是一种配置管理和配置工具,类似于 Chef 和 Puppet,旨在实现多层应用部署和云配置的自动化。 Ansible 用 Python 编写,并使用 YAML 语法来描述自动化任务,这使得 Ansible 易学易用。
虽然可以使用 Ansible 来供应 VPC 资源和安装软件,但此部分使用 Terraform 来供应 VPC 资源,使用 Ansible 来部署软件。
准备工作
此部分同时使用 Terraform 和 Ansible。
- 遵循指示信息在工作站上 安装 Terraform 和 IBM Cloud Terraform 的提供程序插件。
- 遵循 这些指示信息 以安装 Ansible。
Ansible Playbook
Ansible Playbook 提供了要运行的任务。 以下示例具有安装 nginx 和上传脚本所需的一组任务。 您将注意到这些任务与早先讨论的 cloud-init
脚本很类似。 uploaded.sh
脚本完全相同。
- hosts: FRONT_NIC_IP BACK_NIC_IP
remote_user: root
tasks:
- name: update apt cache manual
# this should not be required but without it the error: Failed to lock apt for exclusive operation is generated
shell: apt update
args:
executable: /bin/bash
- name: update apt cache
apt:
update_cache: yes
- name: ensure nginx is at the latest version
apt:
name: nginx
state: latest
notify:
- restart nginx
- name: execute init.bash
script: ./init.bash
- name: upload execute uploaded.sh
script: ../shared/uploaded.sh
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
Ansible 清单
Ansible 可以同时针对基础架构中的多个系统工作。 Ansible 清单包含这些系统的列表。 本教程提供了一个脚本 inventory.bash
根据Terraform输出生成
Ansible 清单。
#!/bin/bash
TF=tf
printf 'all:
children:
FRONT_NIC_IP:
hosts:
%s
BACK_NIC_IP:
hosts:
%s
' $(cd $TF; terraform output -raw FRONT_NIC_IP) $(cd $TF; terraform output -raw BACK_NIC_IP)
供应子网和虚拟服务器实例
目录 vpc-app-deploy/ansible/tf
包含 一个 Terraform 配置,与上一节描述的配置类似,只是删除了软件安装部分。 Ansible 脚本将通过镜像来安装软件,然后从工作站上传软件。
- 对于此示例,请切换到 Ansible 脚本文件夹:
cd $CHECKOUT_DIR/vpc-app-deploy/ansible/tf
- 初始化 Terraform:
terraform init
- 应用 Terraform 套餐:
terraform apply
- 查看套餐生成的输出:
terraform output
- 生成 Ansible 清单:
cd .. && ./inventory.bash > inventory
- 在前端服务器上供应软件:
ansible-playbook -T 40 -l FRONT_NIC_IP -u root \ --ssh-common-args "-F ../../scripts/ssh.notstrict.config -o ProxyJump=root@$(cd tf; terraform output -raw BASTION_IP_ADDRESS)" \ -i inventory lamp.yaml
- 在后端服务器上供应软件:
ansible-playbook -T 40 -l BACK_NIC_IP -u root \ --ssh-common-args "-F ../../scripts/ssh.notstrict.config -o ProxyJump=root@$(cd tf; terraform output -raw BASTION_IP_ADDRESS)" \ -i inventory lamp.yaml
测试虚拟服务器的配置
既然 Terraform 已经部署了资源并且 Ansible 安装了软件,现在可以验证它们是否已正确供应。
- 验证前端虚拟服务器实例是否可访问,并具有对因特网的出站访问权:
命令输出应该如下:../test_provision.bash $(cd tf && terraform output -raw FRONT_IP_ADDRESS) INTERNET hi
success: httpd default file was correctly replaced with the following contents: INTERNET success: provision of file from on premises worked and was replaced with the following contents: hi
- 验证后端是否可通过防御主机访问,以及是否无权访问因特网:
命令输出应该如下:../test_provision.bash $(cd tf && terraform output -raw BACK_NIC_IP) ISOLATED hi "ssh -F ../../scripts/ssh.notstrict.config root@$(cd tf && terraform output -raw FRONT_NIC_IP) -o ProxyJump=root@$(cd tf && terraform output -raw BASTION_IP_ADDRESS)"
success: httpd default file was correctly replaced with the following contents: ISOLATED success: provision of file from on premises worked and was replaced with the following contents: hi
除去资源
-
除去由 Terraform 创建的资源:
cd $CHECKOUT_DIR/vpc-app-deploy/ansible/tf
和
terraform destroy
根据资源的不同,可能不会立即将其删除,但会保留 (缺省情况下为 7 天)。 您可以通过永久删除该资源或在保留期内将其复原来回收该资源。 请参阅本文档,以了解如何 使用资源回收。