DevOps项目笔记一: 基于 Ansible 的多节点基础环境自动化
DevOps Lab Phase 1: 基于 Ansible 的多节点基础环境自动化
1. 阶段目标
本项目最终目标是搭建一套“小而全”的 DevOps 实验环境,后续会逐步加入:
- Ansible
- Docker
- Kubernetes
- Java / Spring Boot
- Jenkins
- CI/CD
- ELK
- 私有镜像仓库
- 日志收集
- 滚动发布
- 故障排查
- 版本回滚
Phase 1 不安装 Kubernetes,而是先解决最基础的问题:
虚拟机规划
↓
固定主机身份
↓
网络互通
↓
SSH 免密
↓
Ansible 控制
↓
统一 Linux 初始化
↓
K8s 节点内核初始化
↓
固定 IP
↓
Git / Gitee 保存项目
完成这一阶段后,后面的 Docker、Kubernetes 等软件就可以通过 Ansible 自动化安装,而不需要逐台 SSH 操作。
2. 实验环境规划
宿主机内存只有 16GB,因此不能给 5 台虚拟机都分配 4GB。
| 主机 | IP | 用户 | 内存 | 用途 |
|---|---|---|---|---|
| k8s-master | 192.168.205.141 | master | 2GB | Kubernetes Control Plane |
| k8s-node1 | 192.168.205.142 | node1 | 2GB | Kubernetes Worker |
| k8s-node2 | 192.168.205.143 | node2 | 2GB | Kubernetes Worker |
| devops | 192.168.205.144 | devops | 2GB | Ansible / 后续 Jenkins、Registry |
| elk | 192.168.205.145 | elk | 4GB | Elasticsearch / Logstash / Kibana |
- 操作系统: Ubuntu 20.04
- 网络: 网段
192.168.205.0/24,网关192.168.205.2 - 网卡:
ens33 - 网络管理: NetworkManager
3. 确认虚拟机网络
首先在每台机器查看网卡和 IP:
ip -br addr
例如 ELK:
lo UNKNOWN 127.0.0.1/8
ens33 UP 192.168.205.145/24
查看路由:
ip route
得到类似:
default via 192.168.205.2 dev ens33
192.168.205.0/24 dev ens33 ...
此时发现地址原本来自 DHCP,因此后面还需要转换为静态 IP。
4. 设置五台机器的 hostname
在 Master:
sudo hostnamectl set-hostname k8s-master
在 Node1:
sudo hostnamectl set-hostname k8s-node1
在 Node2:
sudo hostnamectl set-hostname k8s-node2
在 DevOps:
sudo hostnamectl set-hostname devops
在 ELK:
sudo hostnamectl set-hostname elk
5. 测试虚拟机之间的网络
在 devops 上测试其他节点:
ping -c 2 192.168.205.141
ping -c 2 192.168.205.142
ping -c 2 192.168.205.143
ping -c 2 192.168.205.145
测试 VMware 网关:
ping -c 2 192.168.205.2
测试外网:
ping -c 2 8.8.8.8
测试 DNS:
ping -c 2 www.baidu.com
6. 把 devops 作为 Ansible 控制节点
在 devops 上安装 Ansible:
sudo apt update
sudo apt install -y ansible openssh-client vim git
检查版本:
ansible --version
当前实际版本:
Ansible 2.9.6
Python 3.8.2
7. 配置 SSH 免密登录
在 devops 生成 SSH Key:
ssh-keygen -t ed25519
复制公钥到各节点:
ssh-copy-id master@192.168.205.141
ssh-copy-id node1@192.168.205.142
ssh-copy-id node2@192.168.205.143
ssh-copy-id elk@192.168.205.145
测试:
ssh master@192.168.205.141 hostname
ssh node1@192.168.205.142 hostname
ssh node2@192.168.205.143 hostname
ssh elk@192.168.205.145 hostname
8. 创建 DevOps Lab 项目目录
mkdir -p ~/devops-lab/ansible/{inventory,scripts}
cd ~/devops-lab/ansible
当前目录规划:
devops-lab/
└── ansible/
├── ansible.cfg
├── init.yml
├── network.yml
├── inventory/
│ └── hosts.ini
└── scripts/
└── init.sh
9. 编写 Ansible Inventory
创建 inventory/hosts.ini:
[k8s_control_plane]
k8s-master ansible_host=192.168.205.141 ansible_user=master
[k8s_workers]
k8s-node1 ansible_host=192.168.205.142 ansible_user=node1
k8s-node2 ansible_host=192.168.205.143 ansible_user=node2
[k8s_nodes:children]
k8s_control_plane
k8s_workers
[devops_servers]
devops ansible_host=192.168.205.144 ansible_connection=local
[elk_servers]
elk ansible_host=192.168.205.145 ansible_user=elk
10. 配置 ansible.cfg
创建 ansible.cfg:
[defaults]
inventory = inventory/hosts.ini
host_key_checking = False
11. 第一次测试 Ansible
ansible all -m ping
12. 验证 sudo 权限
ansible all -b -m command -a "whoami"
13. 编写统一初始化脚本 init.sh
创建 scripts/init.sh 详情见代码仓库
devops-lab
https://gitee.com/knight-puno/devops-lab
14. init.sh 做了什么
所有节点都会统一完成:
- 设置 hostname
- 安装基础工具
- 启用 SSH
- 启用 chrony
- 配置
/etc/hosts
15. Kubernetes 节点额外初始化
对于 k8s-master、k8s-node1、k8s-node2,脚本还会做以下准备:
- 关闭 Swap
- 加载 overlay
- 加载 br_netfilter
- 开启 IPv4 Forwarding
| 操作 | 作用 | 不做会怎样 |
|---|---|---|
| 关闭 Swap | 让 Kubelet 准确判断节点真实可用内存 | Kubelet 启动报错,集群初始化失败 |
| 加载 overlay | 提供 OverlayFS 内核支持 | 容器运行时无法正常工作 |
| 加载 br_netfilter | 让 Linux bridge 流量经过 iptables | Service 负载均衡失效 |
| 开启 IPv4 转发 | 允许 Linux 内核转发数据包 | CNI 插件报错,Pod 无法通信 |
16. 编写 init.yml
创建 init.yml:
---
- hosts: k8s_nodes
tasks:
- name: Initialize k8s nodes
script: "./scripts/init.sh {{ ansible_hostname }} k8s"
- hosts: devops_servers
tasks:
- name: Initialize devops server
script: "./scripts/init.sh {{ ansible_hostname }} common"
- hosts: elk_servers
tasks:
- name: Initialize elk server
script: "./scripts/init.sh {{ ansible_hostname }} common"
17. Ansible 2.9 的 script 兼容问题
将 script 模块写成 free-form 形式以避免兼容性问题。
18. Playbook 语法检查
ansible-playbook --syntax-check init.yml
19. 先灰度测试一个 Worker
ansible-playbook init.yml --limit k8s-node1
20. 验收 k8s-node1
ansible k8s-node1 -a "hostname"
ansible k8s-node1 -a "swapon --show"
ansible k8s-node1 -a "sysctl net.ipv4.ip_forward"
ansible k8s-node1 -m shell -a "lsmod | grep -E 'overlay|br_netfilter'"
ansible k8s-node1 -a "getent hosts k8s-master"
21. 初始化全部服务器
ansible-playbook init.yml
22. 批量检查服务器状态
ansible all -a "hostname"
ansible all -a "free -h"
23. K8s 三节点综合检查
ansible k8s_nodes -m shell -a 'echo "===$(hostname)==="; swapon --show; sysctl net.ipv4.ip_forward; lsmod | grep -E "overlay|br_netfilter"'
24. 为什么还需要固定 IP
Kubernetes 尤其是 Control Plane 不适合随意更换 IP,因此需要将 5 台全部改为静态地址。
25. 确认网络由 NetworkManager 管理
systemctl is-active NetworkManager
nmcli device status
26. 创建 network.yml
创建 network.yml,该 Playbook 负责把当前 DHCP 地址转换为静态 IP,IP 直接从 Inventory 的 ansible_host 变量读取。
27. 为什么 network.yml 使用 serial: 1
修改服务器网络属于高风险操作,使用 serial: 1 确保一次只修改一台,避免整个环境同时断开。
28. network.yml 中遇到的 devops IP 问题
必须在 Inventory 中为 devops 主机显式设置 ansible_host=192.168.205.144,否则变量解析会出错。
29. 查看 ansible_host
ansible all -m debug -a "var=ansible_host"
30. 先灰度测试静态 IP
ansible-playbook network.yml --limit k8s-node1
31. 验证静态 IP
ansible k8s-node1 -m ping
ansible k8s-node1 -m shell -a "ip -4 -br addr show ens33"
ansible k8s-node1 -m shell -a "ip route | grep default"
32. 测试静态网络的 Internet 与 DNS
ping -c 2 192.168.205.2
ping -c 2 8.8.8.8
getent hosts www.baidu.com
33. 批量配置静态 IP
# 排除 devops
ansible-playbook network.yml --limit 'all:!devops'
# 最后单独操作 devops
ansible-playbook network.yml --limit devops
34. 最终静态 IP
| 主机 | IP | 子网掩码 |
|---|---|---|
| k8s-master | 192.168.205.141 | /24 |
| k8s-node1 | 192.168.205.142 | /24 |
| k8s-node2 | 192.168.205.143 | /24 |
| devops | 192.168.205.144 | /24 |
| elk | 192.168.205.145 | /24 |
- 网关: 192.168.205.2
- DNS: 192.168.205.2, 8.8.8.8
- NetworkManager:
ipv4.method=manual
35. 当前仓库文件
devops-lab/
├── README.md
├── .gitignore
├── docs/
│ └── phase1.md
└── ansible/
├── ansible.cfg
├── init.yml
├── network.yml
├── inventory/
│ └── hosts.ini
└── scripts/
└── init.sh
36. 将项目纳入 Git
cd ~/devops-lab
git init
git add .
git commit -m "feat: complete phase1 infrastructure initialization"
37. 关联 Gitee
git remote add origin https://gitee.com/knight-puno/devops-lab.git
git branch -M master
git push -u origin master
38. Phase 1 最终验收
- 五台虚拟机互通 OK
- 五台 hostname OK
- SSH 免密 OK
- Ansible Inventory OK
-
ansible all -m pingOK - Ansible sudo OK
- Linux 公共初始化 OK
-
/etc/hostsOK - chrony OK
- K8s 三节点 Swap=0 OK
39. Phase 1 中最重要的经验
- 不要一开始就手工维护所有服务器:使用 Ansible 进行集中管理。
- 自动化必须考虑幂等与重复执行:配置文件应该做到执行一次正常,执行第二次也正常。
- 自动化修改网络必须灰度:采用先单节点验证,再批量执行,并使用
serial: 1。 - 软件版本会影响自动化语法:注意 Ansible、Python 等软件的版本兼容性。
- Kubernetes 集群创建前必须固定网络基础:提前解决 hostname、IP、DNS、swap、内核参数等问题。
40. 下一阶段
Phase 1 已结束,接下来请参考 Phase 2: Docker + Kubernetes Container Runtime。
计划新增:
ansible/
├── docker.yml
├── kubernetes.yml
└── scripts/
├── docker-install.sh
├── cri-dockerd-install.sh
└── k8s-install.sh
下一步首先实现:
Ansible
↓
安装 Docker Engine
↓
配置 Docker daemon
↓
systemd cgroup
↓
启动 Docker
↓
验证 docker info
↓
安装 cri-dockerd
↓
启动 cri-docker.service
↓
验证 /run/cri-dockerd.sock
- Docker 部署到:
k8s-master,k8s-node1,k8s-node2,devops - cri-dockerd 只部署到:
k8s-master,k8s-node1,k8s-node2
更多推荐

所有评论(0)