用Ansible部署服务器
常用系统部署工具
系统部署工具其实已经有很多了,从比较原始的用shell script开始用到现在,用过和了解过的就有:fabric, SaltStack和Puppet。SaltStack和Puppet我觉得麻烦了点,fabric看上去简单,但实际使用需要写不少代码,本质上比Sheel script好不了多少,只是换成Python的语法会习惯一些而已。
Ansible的大名其实早就听说过,也曾经试图去试试,但是一直没空(其实就是拖延症),这次正好要部署几台服务器,就借这个机会尝试一下,感觉不错。
Ansible的使用例子
这里只讨论Ansible的playbook(剧本)模式。
一般的教程喜欢从最简单的例子开始,但是实际上从来不会这样用的,所以我觉得意义不大,还是从一个实际的例子出发比较好。
现在要举的例子是从一台全新安装的Debian的服务器(比如VPS服务商提供的初始化主机)开始,以root用户登录,安装基本的docker环境等。具体项目包括:
- 修改软件源为合适的镜像
- 更新软件包
- 安装需要的软件包
- 配置时区
- 配置语言
- 修改系统参数
- 安装Docker
- 创建用户并分配docker权限
Ansible playbook结构
最简单的playbook只需要一个yaml文件即可,但并不适合这个例子,所以这里要用一个复杂一点的结构。
- ansible
- group_vars
- all
- inventory
- hosts
- roles
- user
- tasks
- main.yml
- tasks
- debian
- files
- sources.list
- tasks
- main.yml
- files
- docker
- tasks
- main.yml
- tasks
- user
- site.yml
- group_vars
ansible是剧本根目录,下面包含三个子目录:group_vars,inventory,roles和一个yaml文件:site.yml。
- site.yml是项目主文件
- group_vars里是需要用到的变量定义,这里没有用到分组变量,只有全局变量,所以下面只有一个all文件。
- inventory里放的主机定义,在hosts文件里。
- roles是剧本角色,类似子剧本的功能,这里定义了三个:user,debian,docker。分别用于公共配置(这里是用户创建),debian系统基础安装配置,docker是安装配置docker。
roles的结构是类似的,这里只用到了两个子目录:files和tasks。files用于存放需要用到的文件,比如软件包源配置,tasks下只简单地用了一个main.yml。如果需要在文件中使用可变内容,还会需要使用templates,后续再说。
site.yml
---
- name: Init server
hosts: myserver
roles:
- debian
- docker
- user
这是一个典型的Ansible剧本文件,用的是YAML格式,其中的---
是playbook步骤开始标志,name是步骤名称,会在运行时显示,hosts是指定主机,可以使用all表示所有主机,具体的主机定义在inventory/hosts里,后面会说。roles则指明要调用的子剧本(角色)。
group_vars
需要用到的变量,比如可以定义一个代理配置,后面可以放到环境变量里使用。
proxy_env:
http_proxy: "http://localhost:8123"
https_proxy: "http://localhost:8123"
hosts
[web]
web.yourserver.com
svrproxy ansible_host=127.0.0.1 ansible_port=2201
[app]
svrapp ansible_host=127.0.0.1 ansible_port=2202
[myserver:children]
web
app
[myserver:vars]
ansible_user=root
这是一个稍微复杂的结构。
首先,可以在文件的第三段看到在剧本里指定的hosts名:myserver,它是一个主机组,包含两个子组:web和app,其中web子组又包括两台主机:一个是可以外网直接通过22端口访问的主机,另一个是通过ssh tunnel映射到本地的内网主机。
最后,需要注意myserver:vars
,这里指定了整个myserver组都默认使用这个变量,指定了登录的用户是root。
debian角色定义
debian角色用于安装系统基本环境。
main.yml
---
- name: copy sources.list
copy:
src: sources.list
dest: /etc/apt/sources.list
owner: root
group: root
mode: '0644'
- name: apt update and upgrade
apt:
upgrade: yes
update_cache: yes
install_recommends: no
environment: "{{ proxy_env }}"
- name: install packages
apt:
pkg:
- sudo
- vim
- rsync
- apt-transport-https
- ca-certificates
- wget
- software-properties-common
- gnupg2
- curl
update_cache: no
install_recommends: no
autoremove: yes
environment: "{{ proxy_env }}"
- name: Set timezone to Asia/Shanghai
timezone:
name: Asia/Shanghai
- name: Ensure a locale exists
locale_gen:
name: en_US.UTF-8
state: present
- name: Update sysctl vm.max_map_count
sysctl:
name: vm.max_map_count
value: '262144'
reload: yes
各步骤功能如描述所说:
- 更新软件源配置文件(sources.list中为自已喜欢的镜像源)
- 更新软件包
- 安装必要的软件包
- 设置时区
- 设置语言
- 更新sysctl参数(运行Elasticsearch需要这个参数)
其中proxy_env
变量就是在group_vars
里定义的,用于指定使用代理,如果变量内容为空或不存在,则不使用代理。
这个角色有一点局限性就是:
软件源配置文件是写死的,所以只能用于指定版本的debian,如果需要用于不同版本甚至是ubuntu等则需要使用templates来创建可变内容的软件源配置文件。
另一个可扩展的点在于:包操作指定使用了apt,如果使用ansible的通用包管理命令则可以支持不同的OS,比如CentOS。
这两点以后另外再说。
sources.list
略
docker角色定义
用于安装docker环境。
main.yml
---
- name: Add Apt signing key from official docker repo
apt_key:
url: "https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg"
state: present
environment: "{{ proxy_env }}"
- name: add docker official repository
apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable"
state: present
environment: "{{ proxy_env }}"
- name: apt update and upgrade for docker
apt:
name: '*'
state: latest
update_cache: yes
install_recommends: no
force_apt_get: yes
environment: "{{ proxy_env }}"
- name: actually install docker
apt:
pkg:
- docker-ce
- docker-compose
state: latest
update_cache: no
install_recommends: no
environment: "{{ proxy_env }}"
基本就是以下步骤:
- 增加APT KEY
- 增加软件源
- 更新软件源
- 安装docker
其中用到了两个ansible变量,用于兼容不同系统——Debian或Ubuntu的不同版本。
ansible_distribution
: 系统发行版,Debian或Ubuntu。| lower
是一个变量转换函数,用于转成小写,详见jinja2(Ansible用的模板引擎)的文档。ansible_distribution_release
: 发行版的版本名,比如:Debian 10是buster,Ubuntu 18.04是bionic。
user角色定义
用于创建用户及相应配置。
main.yml
---
- name: add group
group:
name: raptor
- name: add user
user:
name: raptor
password: $1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.
shell: /bin/bash
group: raptor
groups:
- sudo
- docker
append: yes
这个就很简单直接了,没什么好说的。密码的生成方法如下:
python3 -c 'import crypt; print(crypt.crypt("This is my Password", "$1$SomeSalt$"))'
需要注意的是,crypt是系统相关的,必须在Linux系统下运行这个命令才能得到正确的结果,在macOS下生成的不对。
运行playbook
现在到了实践的时候了。先检查一下,在hosts里配置了正确的主机地址和端口,用户名是root,然后在site.yml所在的位置运行:
ansible-playbook -i inventory/hosts site.yml
即可连上服务器并按步骤执行所有操作。
如果不是使用证书登录,而是用密码的话,需要加上--ask-become-pass
参数输入密码。如果不用root用户……续篇再说吧。
推送到[go4pro.org]