尝试使用Ansible部署Tomcat容器
Ansible是什么?
Ansible是一种用于自动化配置管理、操作系统和软件设置的工具。从Ansible服务器连接到管理目标服务器,并执行部署操作。部署使用名为Playbook的YAML格式指令文件。
本次所构成的环境
大致的流程如下:
1. 安装Ansible
2. 创建和分发密钥对
3. 创建清单文件
4. 创建Dockerfile
5. 创建Playbook
6. 执行Playbook
7. 进行操作确认
服务器环境如下:
Ansible服务器:RHEL8.2
管理目标服务器:RHEL8.2
在RHEL8中,管理用户将使用普通用户而不是root用户。此外,容器引擎将使用Podman而不是Docker。
安装Ansible
Ansible是一个用Python编写的应用程序,安装使用pip而不是dnf(yum)。Python可以使用2.x和3.x版本,但这次我想使用3.x版本进行安装。
我要安装pip。
$ sudo yum install python3-pip
使用安装的pip工具来安装Ansible。
为了将Ansible的使用用户更改为常规用户(ec2-user),我们将使用–user选项。
$ pip3 install ansible --user
$ ansible --version
ansible 2.10.5
config file = None
configured module search path = ['/home/ec2-user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/ec2-user/.local/lib/python3.6/site-packages/ansible
executable location = /home/ec2-user/.local/bin/ansible
python version = 3.6.8 (default, Aug 18 2020, 08:33:21) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
一切顺利完成了安装。
创建和分发密钥对
为了通过SSH通信进行部署,Ansible会预先向受管服务器分发公钥,以实现在SSH通信中无需密码的连接。
首先,使用ssh-keygen命令创建密钥对。
$ ssh-keygen -t rsa
生成将会产生私钥id_rsa和公钥id_rsa.pub。
$ ls -l /home/ec2-user/.ssh/
total 12
-rw-------. 1 ec2-user ec2-user 388 Feb 11 04:11 authorized_keys
-rw-------. 1 ec2-user ec2-user 2655 Feb 11 04:19 id_rsa
-rw-r--r--. 1 ec2-user ec2-user 611 Feb 11 04:19 id_rsa.pub
将公钥添加到管理服务器。
虽然可以使用带有密码的SSH通信在管理服务器上进行SCP或SSH分发,但由于这次刚刚创建了EC2实例,所以只能使用通过下载私钥文件进行SSH通信的方式。
我认为在EC2实例上放置私钥文件在安全上是不可取的,因此我决定直接使用Teraterm连接到管理服务器,并将先前创建的id_rsa内容直接添加到authorized_keys中。
如果考虑到完全自动化的部署,如AutoScaling等,这些事情需要认真考虑。
我认为考虑采用在EC2实例启动时下载保存在S3中的公钥的方法是不错的。
这次将跳过手动注册公钥的步骤。
请注册完公钥后先进行一次SSH连接,以更新known_hosts文件。
如果不进行known_hosts文件的注册,似乎在执行ansible命令时会因为需要注册指纹而导致处理失败。
创建库存文件
创建用于定义 Ansible 受管服务器的清单文件。
$ mkdir /home/ec2-user/ansible
$ cd /home/ec2-user/ansible
我创建了一个名为”hosts”的清单文件。
内容如下:
[tomcatservers]
172.31.44.229
172.31.34.31
172.31.XX.XX是管理服务器的私有IP地址。
我们将两台管理服务器归属于名为tomcatservers的组。
为了确认成功创建了清单文件,我们尝试执行Ansible的ping模块。
$ ansible -u ec2-user -i /home/ec2-user/ansible/hosts tomcatservers -m ping
172.31.34.31 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
172.31.44.229 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
如果收到了”pong”的响应,则表示通信成功。
编写Dockerfile
我們接下來將創建一個Dockerfile,用於在管理服務器上分發。
這次我們創建Dockerfile是為了在容器啟動時下載sample.war文件。
以下是创建Dockerfile的内容:
FROM docker.io/library/tomcat
RUN cd /usr/local/tomcat/webapps && wget http://tomcat.apache.org/tomcat-8.5-doc/appdev/sample/sample.war
创建Playbook
Playbook中定义的任务如下:
1. 安装podman
2. 分发Dockerfile
3. 构建Docker镜像
4. 启动Docker容器
在Docker容器启动时,将根据Dockerfile定义的指令下载示例应用程序,并进行应用程序构建。
具体的的Playbook(tomcat.yml)的内容如下。
- hosts: tomcatservers
remote_user: ec2-user
tasks:
- name: install podman
yum:
name: podman
state: present
become: yes
- name: copy Dockerfile
copy:
src: /home/ec2-user/ansible/Dockerfile
dest: /home/ec2-user
- name: build image
command: podman build -t tomcat:1 /home/ec2-user
notify:
- run container
handlers:
- name: run container
command: podman run -d -p 8081:8080 tomcat:1
为了仅在管理员权限下安装Podman,我们使用”become: yes”进行指定。(类似于sudo执行)
执行Playbook
执行已创建的Playbook。
$ ansible-playbook -i /home/ec2-user/ansible/hosts /home/ec2-user/ansible/tomcat.yml
PLAY [tomcatservers] ***************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [172.31.34.31]
ok: [172.31.44.229]
TASK [install podman] **************************************************************************************************************************************************
changed: [172.31.34.31]
changed: [172.31.44.229]
TASK [copy Dockerfile] *************************************************************************************************************************************************
changed: [172.31.34.31]
changed: [172.31.44.229]
TASK [build image] *****************************************************************************************************************************************************
changed: [172.31.34.31]
changed: [172.31.44.229]
RUNNING HANDLER [run container] ****************************************************************************************************************************************
changed: [172.31.34.31]
changed: [172.31.44.229]
PLAY RECAP *************************************************************************************************************************************************************
172.31.34.31 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.31.44.229 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
确认动作
在Ansible服务器上使用curl命令来运行示例应用程序。
别忘记在AWS安全组中允许8081端口。
$ curl -XGET http://172.31.34.31:8081/sample/
<html>
<head>
<title>Sample "Hello, World" Application</title>
</head>
<body bgcolor=white>
<table border="0">
<tr>
<td>
<img src="images/tomcat.gif">
</td>
<td>
<h1>Sample "Hello, World" Application</h1>
<p>This is the home page for a sample application used to illustrate the
source directory organization of a web application utilizing the principles
outlined in the Application Developer's Guide.
</td>
</tr>
</table>
<p>To prove that they work, you can execute either of the following links:
<ul>
<li>To a <a href="hello.jsp">JSP page</a>.
<li>To a <a href="hello">servlet</a>.
</ul>
</body>
</html>
$ curl -XGET http://172.31.44.229:8081/sample/
<html>
<head>
<title>Sample "Hello, World" Application</title>
</head>
<body bgcolor=white>
<table border="0">
<tr>
<td>
<img src="images/tomcat.gif">
</td>
<td>
<h1>Sample "Hello, World" Application</h1>
<p>This is the home page for a sample application used to illustrate the
source directory organization of a web application utilizing the principles
outlined in the Application Developer's Guide.
</td>
</tr>
</table>
<p>To prove that they work, you can execute either of the following links:
<ul>
<li>To a <a href="hello.jsp">JSP page</a>.
<li>To a <a href="hello">servlet</a>.
</ul>
</body>
</html>
确认无事sample应用程序已经成功运行。