1. ansible 安装 在 ansible 的世界里,我们会通过 inventory 档案来定义有哪些 managed node (被控端),并借由 ssh 和 python 进行沟通。换句话说,当 control machine (主控端) 可以用 ssh 连上 managed node,且被连上的机器里有预载 python 时,ansile 就可以运作了.
1 2 sudo apt install ansible brew install ansible
被控端
要安装 python, 并且能被控制端 ssh
2. ansible 配置 ansible的默认配置文件路径为 /etc/ansible,然而,一个常见的用途是将其安装在一个virtualenv中,在这种情况下,我们一般不会使用这些默认文件。我们可以根据需要在本地目录中创建配置文件。
2.1 inventory文件 您可以创建一个inventory文件,用于定义将要管理的服务器。这个文件可以命名为任何名字,但我们通常会命名为hosts或者项目的名称。
在hosts文件中,我们可以定义一些要管理的服务器。这里我们将定义我们可能要在“web”标签下管理的两个服务器。标签是任意的。
1 2 3 [web] 192.168.22.10 192.168.22.11
现在,让我们将hosts文件设置为指向本地主机local和remote虚拟远程主机。
1 2 3 4 5 [local ] 127.0.0.1 [remote] 192.168.1.2
3. ansible 使用 我们开始对服务器运行任务。ansible会假定你的服务器具有ssh访问权限,通常基于ssh-key。因为ansible使用ssh,所以它需要能够ssh连接到服务器。但是,ansible将尝试以正在运行的当前用户身份进行连接。如果我正在运行ansible的用户是ubuntu,它将尝试以ubuntu连接其他服务器。
Note: 控制端和被控端的用户很显然会不一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 whoami ansible -i ./hosts --connection=local local -m ping 127.0.0.1 | SUCCESS => { "changed" : false , "ping" : "pong" } ansible -i ./hosts remote -m ping 192.168.1.2 | UNREACHABLE! => { "changed" : false , "msg" : "Failed to connect to the host via ssh: ssh: connect to host 192.168.1.2 port 22: Operation timed out\r\n" , "unreachable" : true }
命令说明:
1 2 3 4 5 6 7 8 9 10 -i ./hosts remote,local ,all -m ping -c local | --connection=local 一些常用命令: -i PATH --inventory=PATH --private-key=PRIVATE_KEY_FILE_PATH -m DIRECTORY --module-path=DIRECTORY -c CONNECTION --connection=CONNECTION
3.1 模块(modules) ansible使用“模块”来完成大部分的任务。模块可以做安装软件,复制文件,使用模板等等。
如果我们没有模块,我们将运行任意的shell命令,我们也可以使用bash脚本。这是一个任意shell命令看起来像在ansible(它使用的shell模块!):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ansible -i ./hosts local --connection=local -m shell -a 'ls' 127.0.0.1 | SUCCESS | rc=0 >> README.md hosts nginx.yml roles ansible -i ./hosts remote -b --become-user=root -m shell -a 'yum install nginx' 172.24.120.46 | UNREACHABLE! => { "changed" : false , "msg" : "Failed to connect to the host via ssh: liuwei@172.24.120.46: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).\r\n" , "unreachable" : true }
命令说明:
1 2 3 4 -b --become-user=root -a
要在centos服务器上安装软件,“yum”模块将运行相同的命令,但确保幂等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ansible -i ./hosts remote -v -m yum -a 'name=nginx state=installed update_cache=true' -u root -k No config file found; using defaults SSH password: xxx 172.24.120.46 | SUCCESS => { "changed" : false , "msg" : "" , "rc" : 0, "results" : [ "1:nginx-1.12.2-3.el7.x86_64 providing nginx is already installed" ] } ansible -i ./hosts remote -v -m yum -a 'name=nginx state=installed update_cache=true' -u liuwei -k -s -K SSH password: xxx SUDO password[defaults to SSH password]: xxx 172.24.120.46 | SUCCESS => { "changed" : false , "msg" : "" , "rc" : 0, "results" : [ "1:nginx-1.12.2-3.el7.x86_64 providing nginx is already installed" ] }
命令说明:
1 2 3 4 5 6 7 8 9 10 -v -m apt -a 'name=nginx state=installed update_cache=true' 常用命令: -u USERNAME | --user=USERNAME -k | --ask-pass -s | --sudo -K | --ask-sudo-pass
这将使用yum模块来更新存储库缓存并安装nginx(如果没有安装)。 运行任务的结果是”changed”: false。这表明没有变化; 我已经使用该shell模块安装了nginx 。好的是,我可以一遍又一遍地运行这个命令,而不用担心它会改变预期的结果 - nginx已经安装,ansible知道,并且不尝试重新安装它。
3.2 剧本(playbooks) playbook可以运行多个任务,并提供一些更高级的功能。让我们将上述任务移到一本剧本中。在ansible中剧本(playbooks)和角色(roles)都使用yaml文件定义。
nginx.yml:(通过yaml写所需参数)
1 2 3 4 5 6 7 8 9 - hosts: remote become: yes become_user: root tasks: - name: Install Nginx yum: name: nginx state: installed update_cache: true
这将使用inventory文件中[remote]标签下的服务器hosts。在我们的tasks文件中使用become并become_user再次使用ansible来sudo以root用户身份运行命令,然后传递playbook文件。使用一个yaml playbook文件,我们需要使用这个ansible-playbook命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ansible-playbook -i ./hosts nginx.yml -k -K SSH password: SUDO password[defaults to SSH password]: PLAY [remote] *************************************************************************************************************************************************************************** TASK [Gathering Facts] ****************************************************************************************************************************************************************** ok: [172.24.120.46] TASK [Install Nginx] ******************************************************************************************************************************************************************** ok: [172.24.120.46] PLAY RECAP ****************************************************************************************************************************************************************************** 172.24.120.46 : ok=2 changed=0 unreachable=0 failed=0
我们在运行过程中获得了一些有用的反馈,包括“可执行任务”运行及其结果。在这里我们看到所有运行都ok,但没有改变。
3.3 处理程序(handlers) 处理程序与任务完全相同(它可以做task可以做的任何事),但只有当另一个任务调用它时才会运行。您可以将其视为事件系统的一部分; 处理程序将通过其侦听的事件调用进行操作。 这对于运行任务后可能需要的“辅助”操作非常有用,例如在配置更改后安装或重新加载服务后启动新服务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - hosts: remote become: yes become_user: root tasks: - name: Install Nginx yum: name: nginx state: installed update_cache: true notify: - Start Nginx handlers: - name: Start Nginx service: name: nginx state: started
这里我们添加一个notify指令到安装任务。这将在任务运行后通知名为“Start Nginx”的处理程序。然后我们可以创建名为“Start Nginx”的处理程序。此处理程序是通知“Start Nginx”时调用的任务。 这个特定的处理程序使用服务模块,它可以启动,停止,重启,重新加载(等等)系统服务。在这种情况下,我们告诉ansible,我们要启动Nginx。
如果我已经安装了nginx,则安装nginx任务将不会运行,通知程序也将不会被调用。 3.4 更多的任务(more tasks) 接下来,我们可以为此playbook添加更多的任务,并探索其他一些功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 - hosts: local connection: local become: yes become_user: root vars: - docroot: /var/www/serversforhackers.com/public tasks: - name: Add Nginx Repository apt_repository: repo: ppa:nginx/stable state: present register: ppastable - name: Install Nginx apt: pkg: nginx state: installed update_cache: true when: ppastable|success notify: - Start Nginx - name: Create Web Root file: path: '{{ docroot }} ' mode: 775 state: directory owner: www-data group: www-data notify: - Reload Nginx handlers: - name: Start Nginx service: name: nginx state: started - name: Reload Nginx service: name: nginx state: reloaded
现在有三个任务:
1 2 3 Add Nginx Repository Install Nginx Create Web Root
新的register和when指令,可以实现在某些事情发生后让ansible执行任务的功能。
您还可以注册模块操作的结果,并使用定义的变量根据注册(register)的变量值有条件(when)地执行操作。例如,注册通过shell模块运行命令的结果可以让您访问该命令的stdout。
同时还使用了一个变量, docroot变量在定义vars部分。然后将其用作创建定义目录的文件模块的目标参数。需要注意的是,path配置使用括号NaN,这是Jinja2的模板。为了使ansible能够在括号内解析Jinja2模板变量,该行必须是单引号或双引号 - 例如,path: ‘‘ 而不是path: 。不使用引号将导致错误。 这个playbook可以用通常的命令运行:
1 ansible-playbook -i ./hosts nginx.yml
4. ansible角色(roles) 角色才是ansible的精髓, 每个人可以做出自己的角色让别人使用, 也可以通过ansible-galaxy安装其他人的角色。
角色很适合组织多个相关任务并封装完成这些任务所需的数据。例如,安装nginx可能涉及添加软件包存储库,安装软件包和设置配置。
此外,真实的配置通常需要额外的数据,如变量,文件,动态模板等等。这些工具可以与Playbook一起使用,但是我们可以通过将相关任务和数据组织成一个角色(role, 相关的结构)很快就能做得更好。
角色有一个这样的目录结构:
1 2 3 4 5 6 7 8 roles rolename - files - handlers - meta - templates - tasks - vars
在每个子目录中(eg: files,handlers等等),ansible将自动搜索并读取叫做main.yml的yaml文件。
接下来我们将分解nginx.yml文件内容为不同的组件,并将每个组件放在相应的目录中,以创建一个更干净,更完整的配置工具集。
4.1 创建角色(creating a role) 我们可以使用ansible-galaxy命令来创建一个新角色。此工具可用于将角色保存到ansible的公共注册表,但是我通常只是使用它来在本地创建role的基础目录结构。
1 2 3 4 cd ~/ansible-examplemkdir rolescd rolesansible-galaxy init nginx
目录名称roles是一种惯例,在运行一个playbook时可以用来查找角色。该目录应该始终被命名roles,但并不强制。在roles目录中运行 ansible-galaxy init nginx 命令将创建新角色所需的目录和文件。
我们来看看我们新建的nginx角色的每个部分~/ansible-example/roles/nginx。
4.2.1 文件(files) files目录中没有main.yml文件. 首先,在files目录中,我们可以添加我们要复制到我们的服务器中的文件。对于nginx,我经常复制h5bp的nginx组件配置。我只需从github下载最新的信息,进行一些调整,并将它们放入files目录中。
1 2 3 4 5 ~/ansible-example - roles - - nginx - - - files - - - - h5bp
我们稍后会看到,h5bp配置文件将通过复制模块添加到服务器。
4.2.2 处理程序(handlers) handlers约定必须包含main.yml文件。我们可以把曾经在nginx.yml 剧本中的定义的所有处理程序放入到handlers目录中。
handlers/main.yml 内容:
1 2 3 4 5 6 7 8 9 10 11 12 --- - name: Start Nginx service: name: nginx state: started - name: Reload Nginx service: name: nginx state: reloaded
一旦handlers/main.yml中的处理程序定义好了,我们可以自由地从其他的yaml配置中引用它们。
meta目录中约定必须包含main.yml文件。main.yml文件包含role元数据,包含的依赖关系。如果这个角色依赖于另一个角色,我们可以在这里定义。例如,nginx角色取决于安装ssl证书的ssl角色。
meta/main.yml 内容:
1 2 3 --- dependencies: - { role: ssl }
如果我调用了“nginx”角色,它将尝试首先运行“ssl”角色。 否则我们可以省略此文件,或将角色定义为没有依赖关系:
4.2.4 模板(templates) templates目录中没有main.yml文件,只包含.j2后缀的模板文件。 基于python的Jinja2模板引擎(和django的模板引擎很类似),模板文件可以包含模板变量。这里的文件应该以.j2为类型后缀(eg.uwsgi.j2),提倡但是不强制,也可以取其他的名字。
这是一个nginx服务器(“虚拟主机”)配置的例子。请注意,它使用了稍后在vars/main.yml文件中定义的一些变量。 我们的示例中的nginx配置文件位于templates/serversforhackers.com.conf.j2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 server { listen 80 default_server; server_name {{ domain }}; return 301 https://$server_name $request_uri ; } server { listen 443 ssl default_server; root /var/www/{{ domain }}/public; index index.html index.htm index.php; access_log /var/log/nginx/{{ domain }}.log; error_log /var/log/nginx/{{ domain }}-error .log error ; server_name {{ domain }}; charset utf-8 ; include h5bp/basic.conf; ssl_certificate {{ ssl_crt }}; ssl_certificate_key {{ ssl_key }}; include h5bp/directive-only/ssl.conf; location / { try_files $uri $uri / /index.php$is_args $args ; } location = /favicon.ico { log_not_found off ; access_log off ; } location = /robots.txt { log_not_found off ; access_log off ; } location ~ \.php$ { include snippets/fastcgi.conf; fastcgi_pass unix:/var/run/php7.1-fpm.sock; } }
这是一个相当标准的用于php应用程序的Nginx配置。这里有三个变量:domain
ssl_crt
ssl_key
这三个变量将在变量部分(vars)中定义。
4.2.5 变量(vars) vars目录包含一个main.yml文件, 在main.yml中我们可以列出将要使用的所有变量。
vars/main.yml:
1 2 3 4 --- domain: serversforhackers.com ssl_key: /etc/ssl/sfh/sfh.key ssl_crt: /etc/ssl/sfh/sfh.crt
Note:如果您有敏感信息添加到变量文件中,则可以使用ansible-vault加密文件。 4.2.6 任务(tasks) tasks目录包含一个main.yml文件, 使用角色时运行的主文件是tasks/main.yml文件。看看我们的用例将会是什么样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 --- - name: Add Nginx Repository apt_repository: repo: ppa:nginx/stable state: present - name: Install Nginx apt: pkg: nginx state: installed update_cache: true notify: - Start Nginx - name: Add H5BP Config copy: src: h5bp dest: /etc/nginx owner: root group: root - name: Disable Default Site Configuration file: dest: /etc/nginx/sites-enabled/default state: absent - name: Add SFH Site Config register: sfhconfig template: src: serversforhackers.com.j2 dest: '/etc/nginx/sites-available/{{ domain }} .conf' owner: root group: root - name: Enable SFH Site Config file: src: '/etc/nginx/sites-available/{{ domain }} .conf' dest: '/etc/nginx/sites-enabled/{{ domain }} .conf' state: link - name: Create Web root file: dest: '/var/www/{{ domain }} /public' mode: 775 state: directory owner: www-data group: www-data notify: - Reload Nginx - name: Web Root Permissions file: dest: '/var/www/{{ domain }} ' mode: 775 state: directory owner: www-data group: www-data recurse: yes notify: - Reload Nginx
这一系列任务使得nginx能被完整的安装。任务按照出现的顺序完成以下工作:
1 2 3 4 5 6 7 8 1 添加nginx / stable库 2 安装并启动nginx 3 添加H5BP配置文件 4 从sites-enabled目录中删除文件的符号链接来禁用默认的nginx配置 5 将serversforhackers.com.conf.j2虚拟主机模板复制到nginx配置中,渲染模板 6 通过将其符号链接到sites-enabled目录来启用Nginx服务器配置 7 创建Web根目录 8 更改项目根目录的权限(递归),该目录位于之前创建的Web根目录之上
有一些新的模块(和一些我们已经涵盖的新用途),包括复制,模板和文件模块。通过设置每个模块的参数,我们可以做一些有趣的事情,例如确保文件“不存在”(如果存在则删除它们)的state: absent,或者通过创建一个文件作为符号链接的state: link。您应该检查每个模块的文档,以查看可以用它们完成哪些有趣和有用的事情。
参加官方文档: https://docs.ansible.com/ansible/latest/modules/
4.3 运行角色(running the Role) 要对服务器运行一个或多个角色,我们将重新使用另一个playbook。该playbook与roles目录位于同一个目录中,同一层级。当我们用ansible-playbook命令运行的时候需要先cd进入到该目录中。
让我们创建一个“主”的yaml文件(被ansible-playbook命令执行的文件),该文件定义要使用的角色以及运行它们的主机: 文件~/ansible-example/server.yml位于与roles目录相同的目录中:(注意是和roles目录同层级!!!!!)
1 2 3 4 5 --- - hosts: local connection: local roles: - nginx
所以,我们只是定义角色,而不是在本playbook文件中定义所有的变量和任务。角色负责具体细节。然后我们可以运行角色:
1 ansible-playbook -i ./hosts server.yml
以下是运行nginx角色的playbook文件的输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 PLAY [all] ******************************************************************** GATHERING FACTS *************************************************************** ok: [127.0.0.1] TASK: [nginx | Add Nginx Repository] ****************************************** changed: [127.0.0.1] TASK: [nginx | Install Nginx] ************************************************* changed: [127.0.0.1] TASK: [nginx | Add H5BP Config] *********************************************** changed: [127.0.0.1] TASK: [nginx | Disable Default Site] ****************************************** changed: [127.0.0.1] TASK: [nginx | Add SFH Site Config] ******************************************* changed: [127.0.0.1] TASK: [nginx | Enable SFH Site Config] **************************************** changed: [127.0.0.1] TASK: [nginx | Create Web root] *********************************************** changed: [127.0.0.1] TASK: [nginx | Web Root Permissions] ****************************************** ok: [127.0.0.1] NOTIFIED: [nginx | Start Nginx] *********************************************** ok: [127.0.0.1] NOTIFIED: [nginx | Reload Nginx] ********************************************** changed: [127.0.0.1] PLAY RECAP ******************************************************************** 127.0.0.1 : ok=8 changed=7 unreachable=0 failed=0
我们将所有各种组件放在一起,形成一致的角色,现在已经安装并配置了nginx!
5. ansible事实(facts) 请注意,运行剧本时的第一行总是“收集事实”。 在运行任何任务之前,ansible将收集有关其配置的系统的信息。这些被称为事实,并且包括广泛的系统信息,如CPU核心数量,可用的ipv4和ipv6网络,挂载的磁盘,Linux发行版等等。
事实在“任务”或“模板”配置中通常很有用。例如,nginx通常设置为使用与cpu内核一样多的工作处理器。知道这一点,您可以选择如下设置nginx.conf.j2文件的模板:
1 2 3 4 5 user www-data;worker_processes {{ ansible_processor_cores }};pid /var/run/nginx.pid;
或者如果你具有多个cpu的服务器,则可以使用:
1 2 3 4 5 user www-data;worker_processes {{ ansible_processor_cores * ansible_processor_count }};pid /var/run/nginx.pid;
所有的ansible facts全局变量都是以“anisble_”为前缀,并且可以在其他任何地方使用。 尝试对你的本地机器运行以下内容以查看可用的事实:
1 2 3 4 5 6 ansible -m setup --connection=local localhost ansible -i ./hosts remote -m setup
6. ansible遇到的问题总结 遇到角色没有的问题, ERROR! the role ‘Stouts.ntp’ was not found
通过ansible-galaxy安装
1 ansible-galaxy install stouts.ntp
ansible的全局配置ansible.cfg
如默认是否需要输入密码、是否开启sudo认证、action_plugins插件的位置、hosts主机组的位置、是否开启log功能、默认端口、key文件位置等等。
参见: https://www.cnblogs.com/paul8339/p/6159220.htm
host文件把一个组作为另一个组的子成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [atlanta] host1 host2 [raleigh] host2 host3 [southeast:children] atlanta raleigh [southeast:vars] some_server=foo.southeast.example.com halon_system_timeout=30 self_destruct_countdown=60 escape_pods=2 [usa:children] southeast northeast southwest northwest
atlanta raleigh将作为southeast子组,继承父组southeast中some_server等变量
限制脚本只在指定的ip对应的机器上执行。
-l, –limit
1 ansible-playbook myplaybook.yml -l 10.11.12.13
打标签归类, 指定归类相关的task
1 2 3 4 5 6 7 --- - include: restart.yml tags: - tag2 - include: push.yml tags: - tag1
tags主要目的是单独执行指定的tag,使用-t 或者–tags 表示。旧版本不是这样写的,会直接在include后面加上tags=xxx,但是在新版本的ansible执行时虽然不报错,但是也不执行该tag。
7. 参考资料