组件架构
ansible core : ansible 自身核心模块
host inventory: 主机库,定义可管控的主机列表
connection plugins: 连接插件,一般默认基于 ssh 协议连接
modules:core modules ( 自带模块 ) 、 custom modules ( 自定义模块 )
playbooks :剧本,按照所设定编排的顺序执行完成安排任务
Ansible与Saltstack和puppet的最大区别是Ansible无需在被控端部署任何客户端代理,默认直接通过SSH通道进行远程命令的执行或下发配置;相同点都是具备功能强大、灵活的的系统管理、状态配置,都使用YAML格式来描述配置,都具有丰富的模板及API。
Ansible提供了一个在线的Playbook分享平台,地址是:https://galaxy.ansible.com/,该平台汇聚了各类常用功能的角色,找到适合自己的Role(角色)后,只需要运行“ansible-galaxy install 作者id.角色包名称”就可以安装到本地。
[root@xuegod63 ~]# ansible-galaxy install bennojoy.mysql
- downloading role 'mysql', owned by bennojoy
- downloading role from https://github.com/bennojoy/mysql/archive/master.tar.gz
- extracting bennojoy.mysql to /etc/ansible/roles/bennojoy.mysql
- bennojoy.mysql was installed successfully
[root@xuegod63 ~]# ls /etc/ansible/roles/bennojoy.mysql/
defaults/ handlers/ meta/ README.md tasks/ templates/ vars/
安装
建议使用yum方式安装
先安装在线yum的epel源
[root@xuegod63 ~]# rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
Retrieving http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
warning: /var/tmp/rpm-tmp.tDsKed: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
Preparing... ########################################### [100%]
1:epel-release ########################################### [100%]
生成一下缓存
[root@xuegod63 ~]# yum makecache
[root@xuegod63 ~]# yum list | grep ansible
ansible.noarch 2.1.1.0-1.el6 epel
ansible-inventory-grapher.noarch 1.0.1-2.el6 epel
ansible-lint.noarch 2.0.1-1.el6 epel
ansible1.9.noarch 1.9.6-2.el6.1 epel
安装
[root@xuegod63 ~]# yum install -y ansible1.9.noarch
入门操作
在这里我们用自己创建的目录/var/opt来存放ansible相应的文件
[root@xuegod63 ~]# cd /var/opt
定义主机清单
ansible基于ssh连接inventory中指定的远程主机时,将以此处的参数指定的属性进行
ansible_ssh_port:指定 ssh 端口
ansible_ssh_user:指定 ssh 用户
ansible_ssh_pass:指定 ssh 用户登录是认证密码,明文密码不安全
ansible_sudo_pass:指明 sudo 时候的密码
新建文件hosts
[root@xuegod63 opt]# vim hosts
#增加以下内容
[tomcatserver] #主机组名
192.168.10.64 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=123456
192.168.10.65 #主机IP或主机名
简单测试下主机的连通性
[root@xuegod63 opt]# ansible -i hosts tomcatserver -m ping -k
SSH password:
192.168.10.65 | success >> {
"changed": false,
"ping": "pong"
}
192.168.10.64 | success >> {
"changed": false,
"ping": "pong"
}
一般来说,使用明文密码不安全,所以增加主机无密码访问
生成密钥对
[root@xuegod63 opt]# ssh-keygen -t rsa -P ""
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
10:29:6f:38:e5:e3:da:52:3f:48:ed:7a:ae:ca:db:0a root@xuegod63.cn
The key's randomart image is:
+--[ RSA 2048]----+
| .. |
| . o. |
| *. |
| o =. |
| + oS |
| + . |
| E = + |
| oo.o = |
| ==+=.. |
+-----------------+
拷贝密钥到xuegod64和xuegod65
[root@xuegod63 opt]# ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.10.64
root@192.168.10.64's password:
Now try logging into the machine, with "ssh '192.168.10.64'", and check in:
.ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.
[root@xuegod63 opt]# ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.10.65
root@192.168.10.65's password:
Now try logging into the machine, with "ssh '192.168.10.65'", and check in:
.ssh/authorized_keys
to make sure we haven't added extra keys that you weren't expecting.
anisble命令
ansible [–i 主机文件] [-f 批次] [组名] [–m 模块名称] [–a 模块参数]
模块查询命令
ansible-doc -l 列出所有的模块列表
ansible-doc -s 查看指定模块的参数
常用模块
1.远程命令模块
command:作为ansible的默认模块,可以运行远程权限范围内的所有shell命令;
script:是在远程主机上执行主控端存储的shell脚本,相当于scp+shell组合;
shell:是执行远程主机上的shell脚本
# ansible -i hosts tomcatserver -m command -a "free -m"
2.copy模块
copy:实现主控端向目标主机拷贝文件,类似scp功能
# ansible -i hosts tomcatserver -m copy -a "src=./hosts dest=/tmp/ owner=root group=root mode=0755"
3.file模块
file:设置文件属性。
# ansible -i hosts tomcatserver -m file -a "path=/tmp/hosts mode=0777"
4.stat模块
stat:获取远程文件信息
# ansible -i hosts tomcatserver -m stat -a "path=/tmp/hosts"
5.get_url模块
get_url:实现远程主机下载指定url到本地,支持sha256sum文件校验。
# ansible -i hosts tomcatserver -m get_url -a "url=http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm dest=/tmp/ mode=0440 force=yes"
6.yum模块
yum:linux平台软件包管理。
例子:安装php软件
# ansible -i hosts tomcatserver -m yum -a "name=php state=latest"
7.cron模块
cron:远程主机crontab配置。
# ansible -i hosts tomcatserver -m cron -a "name='list dir' minute='*/30' job='ls /tmp'"
8. mount模块
mount:远程主机分区挂载。
# ansible -i hosts tomcatserver -m mount -a "name=/mnt src=/dev/sda1 fstype=ext4 opts=ro state=present"
9.service模块
service:远程主机系统服务管理。
[root@xuegod63 opt]# ansible -i hosts tomcatserver -m service -a "name=httpd state=restarted"
验证:查看服务启动时间
[root@xuegod64 ~]# ps -eo cmd,pid,lstart,etime | grep httpd
10.sysctl模块
sysctl:远程主机sysctl配置。
# ansible -i hosts tomcatserver -m sysctl -a "name=net.ipv4.ip_forward value=1 reload=yes"
11.user模块
user:远程主机用户管理
# ansible -i hosts tomcatserver -m user -a "name=less state=present"
playbook
Playbook是一个不同于使用ansible命令行执行方式的模式,功能更强大灵活,简单地说,playbook是一个非常简单的配置管理和多主机部署系统。
playbook是由一个或多个”play”组成的列表。play的主要功能在于将事先归为一组的主机装扮成事先通过ansible中的task定义好的角色。
github上提供了大量的实例供大家参考 https://github.com/ansible/ansible-examples
核心元素
- Hosts 执行的远程主机列表
- Tasks 任务集
- Variables 内置变量或自定义变量在playbook中调用
- Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
- Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
- tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
playbooks 中 定义任务:
---
- name: task description 注释 描述信息
module_name: module_args 声明模块:定义 ansible 模块参数
ansible-playbook 执行 命令:
ansible-playbook <site.yml> ... [options]
-C --check #只检测可能会发生的改变,但不真正执行操作
--list-hosts #列出运行任务的主机
--list-tags #列出tag
--list-tasks #列出task
--limit 主机列表 #只针对主机列表中的主机执行
-v -vv -vvv #显示过程
Playbook 是一个由一个或多个 play 组成的文件;play 是针对特定主机或主机组执行的一组有序的任务;每个 playbook 必须包含两部分:
hosts: 运行 playbook 的一组主机
tasks: 需要在主机上运行的任务
除了这两个必须选项,还有一些可选项选项,也可能需要包含在 play 中,如:
name: play 的名称,在运行该 play 时,会在运行过程中显示。
become: 与配置文件中的 become 作用一样,用于提权,当配置文件中禁用提权时,你想要某个 play 使用提权的话,你可以在 play 中添加 become。
playbook 以 yaml 格式编写的,通常以 yml 扩展名保存。yaml 格式使用空格缩进,对于空格的数量没有特别要求,但需要注意:
- 同一级别内的元素必须使用相同的缩进;
- 对于子项目,缩进必须比父项目多
Playbook 以 —- 开头,用于标记文件开始;
第二行的 name 为该 play 的名称;
第三行的 hosts 表示将要运行该 play 的主机;
第四行的 tasks 表示该 play 将要执行的具体任务;
通过缩进,我们可以看出 tasks 一共分为三个部分,也就是三个模块,每个模块由一个 name 开表示该模块的 name,虽然 name 是可选选项,但建议写上,用来作为对该模块执行任务的解释说明,并且 name 的内容会在 playbook 执行此模块时,显示在执行过程中;
name 下面的是模块的名称,在该 play 的 tasks 中一共有三个模块:
apt: 用于安装软件
copy: 用于复制文件或内容
service: 用于操作 service,如启动服务,重启服务等
roles
学习资料:http://www.yunweipai.com/34669.html
角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
运维复杂的场景:建议使用roles,代码复用度高
现生产案例
cnr_gateway.yml
- hosts: cnr_gateway
become: yes
serial: 1
become_method: sudo
gather_facts: yes
roles:
- cnr_gateway
./roles/cnr_gateway/{defaults,handlers,PaxHeader,tasks,templates}
defaults/main.yml
---
# Registry Settings
cnr_gateway_docker_registry: 'registry.cn-hangzhou.aliyuncs.com'
cnr_gateway_registry_user: ''
cnr_gateway_registry_password: ''
# Environment Specific Settings
cnr_gateway_env: development
cnr_gateway_image: cnr_gateway
cnr_gateway_image_tag: latest
# Host specific Settings
cnr_gateway_confdir: '/srv/appvolumes/cnr_gateway'
cnr_gateway_logdir: '/srv/logs'
cnr_gateway_host_port: ''
cnr_gateway_appport: ''
cnr_gateway_network_mode: "bridge"
cnr_gateway_syslog_url: ''
# Eurka
codemaster_codecamp_app_api_oos_enable: false
# App Setting
cnr_gateway_config_server_port: ""
cnr_gateway_config_eureka_instance_hostname: ""
cnr_gateway_config_apollo_meta: ""
./handlers/main.yml
---
- name: Restart container
command: /usr/bin/docker restart "{{ cnr_gateway_container_name }}"
./tasks/main.yml
---
- name: Modify VServer Weight To Zero
connection: local
ali_slb:
alicloud_access_key: '{{ alicloud_access_key }}'
alicloud_secret_key: '{{ alicloud_secret_key }}'
alicloud_region: '{{ cnr_gateway_alicloud_region }}'
vserver_group_id: '{{ cnr_gateway_vserver_group_id }}'
backend_servers:
- ServerId: '{{ instance_id }}'
Port: '{{ cnr_gateway_host_port }}'
Weight: 0
when: cnr_gateway_slb_enable
- name: create log file
file:
path: '{{ cnr_gateway_logdir }}'
owner: root
group: root
mode: 0755
state: directory
- name: Setup application data tree
file:
path: '{{ cnr_gateway_confdir }}'
owner: root
group: root
mode: 0755
state: directory
- name: Setup application data tree
file:
path: '{{ cnr_gateway_confdir }}/log/'
owner: root
group: root
mode: 0757
recurse: yes
state: directory
- name: Setup application data tree
file:
path: '{{ cnr_gateway_confdir }}/log/common'
owner: root
group: root
mode: 0757
recurse: yes
state: directory
- name: Install application configuration
template:
src: 'config.yml.j2'
dest: '{{ cnr_gateway_confdir }}/application-{{ cnr_gateway_env }}.yml'
owner: root
group: root
mode: 0644
notify: Restart container
- name: Login to docker registry
docker_login:
registry: '{{ cnr_gateway_docker_registry }}'
username: '{{ cnr_gateway_registry_user }}'
password: '{{ cnr_gateway_registry_password }}'
- name: Pull initial docker image from registry
docker_image:
name: '{{ cnr_gateway_docker_registry }}/codemaohub/{{ cnr_gateway_image }}:{{ cnr_gateway_image_tag }}'
state: present
- block:
- name: Check if the port exists
wait_for:
port: "{{ cnr_gateway_host_port }}"
state: stopped
delay: 0
timeout: 1
rescue:
- name: Change Application Out Of Service
uri:
url: 'http://127.0.0.1:{{ cnr_gateway_host_port }}/eureka/out_of_service'
method: PUT
register: response
failed_when: "response.status != 200"
- name: Waiting for cache clean
pause:
minutes: 2
when: cnr_gateway_oos_enable
- name: Install, update and start containers
docker_container:
name: '{{ cnr_gateway_container_name }}'
image: '{{ cnr_gateway_docker_registry }}/codemaohub/{{ cnr_gateway_image }}:{{ cnr_gateway_image_tag }}'
restart_policy: 'always'
pull: yes
recreate: yes
state: started
restart: yes
command: "{{ cnr_gateway_start_command }} --spring.profiles.active={{ cnr_gateway_env }}"
ports:
- "{{ cnr_gateway_host_port }}:{{ cnr_gateway_app_port }}"
volumes:
- '{{ cnr_gateway_confdir }}:/usr/src/app/config'
- '{{ cnr_gateway_logdir }}:/localdata'
etc_hosts: "{{ all_etc_hosts }}"
# Use the defaults bridge network
# Mandatory for production!
network_mode: "{{ cnr_gateway_network_mode }}"
- name: Immediate Execution Handlers
meta: flush_handlers
- name: Wait for container to become available
wait_for:
port: '{{ cnr_gateway_host_port }}'
delay: 5
timeout: 45
when: cnr_gateway_healthcheck_enabled
- name: Validating application healthcheck
uri:
url: 'http://{{ cnr_gateway_healthcheck_host }}:{{ cnr_gateway_healthcheck_port }}{{ cnr_gateway_healthcheck_endpoint}}'
method: GET
return_content: true
register: response
retries: 5
delay: 15
until: response is succeeded
failed_when: cnr_gateway_healthcheck_responsestring not in response.content
when: cnr_gateway_healthcheck_enabled
- name: Configure firewall to accept SLB health check
ufw:
rule: allow
port: "{{ cnr_gateway_host_port }}"
proto: tcp
to_ip: "{{ ansible_eth0['ipv4']['address'] }}"
- name: Modify VServer Weight To 100
connection: local
ali_slb:
alicloud_access_key: '{{ alicloud_access_key }}'
alicloud_secret_key: '{{ alicloud_secret_key }}'
alicloud_region: '{{ cnr_gateway_alicloud_region }}'
vserver_group_id: '{{ cnr_gateway_vserver_group_id }}'
backend_servers:
- ServerId: '{{ instance_id }}'
Port: '{{ cnr_gateway_host_port }}'
Weight: 100
when: cnr_gateway_slb_enable
./templates/config.yml.j2
server:
port: {{ cnr_gateway_config_server_port }}
eureka:
client:
service-url:
defaultZone: {{ cnr_gateway_config_eureka_client_service_url }}
instance:
hostname: {{ cnr_gateway_config_eureka_instance_hostname }}
apollo:
meta: {{ cnr_gateway_config_apollo_meta }}