1. Ansible服务部署入门实战
最近在整理自动化运维工具链时,重新梳理了Ansible的部署流程。作为一款无代理的配置管理工具,Ansible通过SSH协议实现批量操作,特别适合中小规模的环境管理。下面分享一个完整的服务部署练习,涵盖从基础环境搭建到多节点管理的全流程。
提示:本练习基于CentOS 7环境,但原理适用于大多数Linux发行版。所有操作均在普通用户权限下完成,通过sudo提权执行特权命令。
1.1 环境准备与安装
首先在控制节点(管理机)上安装Ansible。EPEL仓库提供了稳定版本,安装过程非常简单:
bash复制# 添加EPEL仓库
sudo yum install -y epel-release
# 安装Ansible核心组件
sudo yum install -y ansible
验证安装是否成功:
bash复制ansible --version
# 应显示类似:ansible 2.9.27
配置SSH免密登录是后续操作的关键。在控制节点生成密钥对并分发到所有被管节点:
bash复制ssh-keygen -t rsa -b 4096
# 将公钥复制到node1节点示例
ssh-copy-id user@node1
1.2 基础配置文件解析
Ansible的核心配置文件位于/etc/ansible目录,其中最重要的两个文件是:
ansible.cfg- 全局配置
ini复制[defaults]
inventory = ./hosts
remote_user = ops
private_key_file = ~/.ssh/id_rsa
host_key_checking = False
hosts- 主机清单文件
ini复制[web_servers]
node1 ansible_host=192.168.1.101
node2 ansible_host=192.168.1.102
[db_servers]
db1 ansible_host=192.168.1.201
注意:生产环境中建议将主机清单文件纳入版本控制,并考虑使用动态Inventory对接CMDB系统。
2. 核心模块使用实践
2.1 软件包管理实战
Ansible的yum模块是管理RPM包的核心工具。以下是安装Nginx的示例playbook:
yaml复制- name: Install and start Nginx
hosts: web_servers
become: yes
tasks:
- name: Install EPEL repo
yum:
name: epel-release
state: present
- name: Install Nginx
yum:
name: nginx
state: latest
update_cache: yes
- name: Enable and start service
service:
name: nginx
enabled: yes
state: started
关键参数说明:
state: present确保软件包安装update_cache: yes相当于执行yum makecacheenabled: yes设置开机自启
2.2 文件分发与模板
copy和template模块用于文件管理。以下是部署自定义Nginx配置的示例:
yaml复制- name: Configure Nginx
hosts: web_servers
become: yes
tasks:
- name: Upload configuration
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: 0644
notify: restart nginx
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
模板文件nginx.conf.j2支持Jinja2语法,可以包含变量和逻辑:
jinja2复制worker_processes {{ ansible_processor_vcpus }};
events {
worker_connections {{ max_connections }};
}
3. 多节点协同部署案例
3.1 Redis集群部署
实现3主机6副本的Redis集群部署:
yaml复制- name: Deploy Redis cluster
hosts: redis_servers
become: yes
vars:
redis_version: 6.2.6
cluster_nodes: "{% for host in groups['redis_servers'] %} {{ hostvars[host].ansible_default_ipv4.address }}:6379 {% endfor %}"
tasks:
- name: Install dependencies
yum:
name: ["gcc", "make", "tcl"]
state: present
- name: Download Redis
get_url:
url: "http://download.redis.io/releases/redis-{{ redis_version }}.tar.gz"
dest: /tmp/redis.tar.gz
- name: Compile and install
command: |
tar xzf /tmp/redis.tar.gz -C /tmp
cd /tmp/redis-{{ redis_version }} && make && make install
creates: /usr/local/bin/redis-server
- name: Create cluster
command: redis-cli --cluster create {{ cluster_nodes }} --cluster-replicas 1
run_once: yes
delegate_to: redis1
3.2 跨模块联动示例
结合yum、service和handler实现完整服务部署:
yaml复制- name: Full stack deployment
hosts: all
become: yes
tasks:
- name: Install common packages
yum:
name: ["vim", "htop", "net-tools"]
state: present
- name: Configure timezone
timezone:
name: Asia/Shanghai
- name: Optimize sysctl
sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
state: present
reload: yes
with_items:
- { key: 'net.ipv4.tcp_tw_reuse', value: '1' }
- { key: 'vm.swappiness', value: '10' }
- name: Reboot if needed
reboot:
msg: "System rebooted for kernel updates"
connect_timeout: 5
reboot_timeout: 600
pre_reboot_delay: 0
post_reboot_delay: 30
when: ansible_kernel is changed
4. 生产环境优化建议
4.1 性能调优技巧
- SSH连接优化:
ini复制[ssh_connection]
pipelining = True
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
- 开启fact缓存(使用redis作为后端):
ini复制[defaults]
fact_caching = redis
fact_caching_timeout = 86400
fact_caching_connection = localhost:6379:0
- 任务并行执行:
yaml复制- name: Parallel execution
hosts: web_servers
strategy: free
serial: 30%
4.2 常见问题排查
- 模块执行失败:
- 检查
-vvv详细日志 - 使用
ignore_errors: yes临时跳过错误任务
- 主机不可达:
bash复制ansible -m ping all
# 检查SSH配置和网络连通性
- 权限问题:
- 确保
become: yes正确设置 - 检查sudoers配置:
bash复制ops ALL=(ALL) NOPASSWD: ALL
- 变量未定义:
- 使用
default()过滤器:
jinja2复制{{ some_var | default('value') }}
5. 进阶部署模式
5.1 蓝绿部署实现
通过动态Inventory实现零停机更新:
yaml复制- name: Blue-green deployment
hosts: localhost
connection: local
vars:
current_env: "blue"
new_env: "green"
tasks:
- name: Provision new servers
ec2:
image: ami-123456
count: 3
instance_tags:
Environment: "{{ new_env }}"
register: ec2_result
- name: Add to load balancer
elb:
name: production-lb
state: present
instance_ids: "{{ item.id }}"
with_items: "{{ ec2_result.instances }}"
- name: Drain old servers
command: |
aws elb deregister-instances-from-load-balancer
--load-balancer-name production-lb
--instances "{{ groups[current_env] }}"
- name: Terminate old instances
ec2:
instance_ids: "{{ groups[current_env] }}"
state: absent
5.2 与Docker集成
使用docker_container模块部署应用:
yaml复制- name: Dockerized app
hosts: app_servers
become: yes
tasks:
- name: Install Docker
yum:
name: docker-ce
state: present
- name: Start Docker
service:
name: docker
enabled: yes
state: started
- name: Pull image
docker_image:
name: nginx:alpine
source: pull
- name: Run container
docker_container:
name: webapp
image: nginx:alpine
ports:
- "8080:80"
volumes:
- "/opt/web:/usr/share/nginx/html"
restart_policy: unless-stopped
6. 监控与维护
6.1 与Prometheus集成
部署node_exporter监控节点:
yaml复制- name: Deploy node_exporter
hosts: all
become: yes
tasks:
- name: Download binary
get_url:
url: https://github.com/prometheus/node_exporter/releases/download/v1.3.1/node_exporter-1.3.1.linux-amd64.tar.gz
dest: /tmp/node_exporter.tar.gz
- name: Install
unarchive:
src: /tmp/node_exporter.tar.gz
dest: /usr/local/bin/
remote_src: yes
extra_opts: "--strip-components=1 */node_exporter"
- name: Create systemd service
template:
src: templates/node_exporter.service.j2
dest: /etc/systemd/system/node_exporter.service
- name: Enable service
systemd:
name: node_exporter
enabled: yes
state: started
6.2 日常维护任务
自动化日志轮转配置示例:
yaml复制- name: Logrotate setup
hosts: all
become: yes
tasks:
- name: Install logrotate
yum:
name: logrotate
state: present
- name: Deploy config
copy:
src: files/app_logrotate
dest: /etc/logrotate.d/app
owner: root
group: root
mode: 0644
- name: Test configuration
command: logrotate -d /etc/logrotate.conf
changed_when: false
实际工作中,Ansible的威力在于将这类基础操作标准化。我通常会建立一个基础角色(base_role),包含这些通用配置,然后通过角色依赖应用到所有主机。对于特殊配置,再通过变量覆盖或额外角色实现。这种模式既保证了统一性,又保留了灵活性。
