本人只是个前端,很早之前就听说过 ansible, terraform 这类运维工具,一直没机会上手玩一下,上个月借着 GCP 刚开通的 300 刀额度业余时间鼓捣了一下,到现在一个多月了,发现真的是个神器啊,特别是如果有个十来台服务器一起执行 playbook 的时候,有种莫名的爽感😄
![]() |
1
defunct9 7 天前
一直用一直爽。但 k8s 比这个爽。
|
![]() |
2
Kirkcong 7 天前
是啊是啊,超爽的,我们 1000+台机器,全靠 ansible
|
3
hausen 7 天前
问题是,好像个人使用没什么使用场景吧?
|
![]() |
4
EyebrowsWhite OP ![]() @defunct9 等玩腻了 ansible 就折腾 k8s ,其实之前尝试上手过,但是如果不用 GKE 之类的基础设施就太复杂了,而如果用的话又没那种感觉 :) 毕竟我不是专业运维,没有业务需求和压力。很巧的是,我在用一个 ansible wireguard role 的时候看到作者就是纯自己搭建的 k8s ,打算后面跟着他的 blog( https://www.tauceti.blog/)搞一下
|
![]() |
5
EyebrowsWhite OP |
![]() |
6
EyebrowsWhite OP |
![]() |
7
Kirkcong 7 天前
@EyebrowsWhite #6 看了下监控系统,目前是 1080 台机器。不会同时执行的,我们有不同的 team ,ansible 机器设置了 crontab 错开时间,总共 65 个 team 。倒不是 ansible 机器承受不住,是因为不同 team 配置不同,执行的 role 不同。
至于最多多少台机器执行,这个没法算,我们没有统计每个 team 机器数量。 |
![]() |
8
Kirkcong 7 天前
|
![]() |
9
guanzhangzhang 7 天前
核心是 jinja2 ,这个熟悉了再会抽配置,就熟练了,很多人都只基础的文件拷贝执行命令啥的
|
![]() |
10
defunct9 7 天前
kubespray 是个好东西,正在用它建新集群,参数多多啊。
|
![]() |
11
EyebrowsWhite OP @Kirkcong 奥奥,感谢解答,我们使用场景不同,我就一个人玩,和你们团队生产用毕竟还是有很大差距
@guanzhangzhang 结合 AI 的话学习起来很快,jinja2 基础用法很简单,就是那些高级的功能比如 Custom Filters 啥的感觉复杂些 |
![]() |
12
EyebrowsWhite OP @defunct9 看起来很强啊,教程还是用的 GCP ,那我不得不试一试了
|
![]() |
13
Kirkcong 7 天前
@EyebrowsWhite #11 我个人的机器也在用 ansible ,包括 k8s 节点的创建,vps 的一些基础配置,比如加 key,创建用户,nfs 挂载,hostname,软件包的安装,有 ansible 会方便很多
|
14
Gannicus5 7 天前
作为一个 SRE ,我没怎么用过哈哈哈
|
![]() |
15
Kirkcong 7 天前
---
# tasks file for common - name: Account management tasks block: - name: Ensure group "admin" exists ansible.builtin.group: name: admin gid: 4141 state: present - name: Accounts configuration ansible.builtin.user: name: "{{ item.name }}" uid: "{{ item.uid }}" state: present group: "{{ item.group }}" loop: "{{ accounts }}" - name: Set up multiple authorized keys ansible.builtin.authorized_key: user: "{{ item.user }}" key: "{{ item.key }}" manage_dir: true loop: "{{ keys }}" - name: Add sudoers for ansible and hola ansible.builtin.lineinfile: path: /etc/sudoers.d/systems line: "{{ item.name }} ALL=(ALL) NOPASSWD:ALL" create: true loop: "{{ accounts }}" when: item.admin | bool - name: Change root password ansible.builtin.user: name: root password: "{{ root_password }}" state: present - name: Change hola password ansible.builtin.user: name: hola password: "{{ user_password }}" state: present - name: Install the packages when os is rhel ansible.builtin.dnf: name: "{{ item.name }}" state: "{{ item.state }}" loop: "{{ packages_rhel }}" when: ansible_os_family == "RedHat" - name: Install the packages when os is debian ansible.builtin.apt: name: "{{ item.name }}" state: "{{ item.state }}" loop: "{{ packages_debian }}" when: ansible_os_family == "Debian" or ansible_os_family == "Ubuntu" become: true ignore_errors: false remote_user: root vars: ansible_ssh_private_key_file: "~/ansi/key" - name: Generate facts block: - name: Create directory for ansible custom facts ansible.builtin.file: state: directory recurse: true path: /etc/ansible/facts.d - name: Chcek if exsit custom facts ansible.builtin.stat: path: /etc/ansible/facts.d/static.fact register: host_facts_stat - name: Install custom fact ansible.builtin.copy: src: static.fact dest: /etc/ansible/facts.d when: not host_facts_stat.stat.exists - name: End the play after first time to create custom facts meta: end_play when: not host_facts_stat.stat.exists become: true ignore_errors: false remote_user: root vars: ansible_ssh_private_key_file: "~/ansi/key" - name: Load custom facts ansible.builtin.setup: filter: ansible_local - name: System configuration tasks block: - name: Re-read facts after adding custom fact ansible.builtin.setup: filter: ansible_local # Upgrade packages # - name: Upgrade all packages for rhel # ansible.builtin.dnf: # name: "*" # state: latest # when: ansible_os_family == "RedHat" # - name: Upgrade all packages for debian # ansible.builtin.apt: # name: "*" # state: latest # when: ansible_os_family == "Debian" or ansible_os_family == "Ubuntu" - name: Set hostname ansible.builtin.hostname: name: "{{ ansible_local['static']['general']['hostname'] }}" when: ansible_local['static']['general']['hostname'] is defined and ansible_local['static']['general']['hostname'] != "" - name: Configure eth0 ip address ansible.builtin.template: src: nmconnection_eth0.j2 dest: /etc/NetworkManager/system-connections/eth0.nmconnection owner: root group: root mode: 0700 register: nmconnection_eth0_result - name: Reload eth0 configuration command: | nmcli connection reload nmcli connection up eth0 when: nmconnection_eth0_result.changed - name: Disable cloud-init network ansible.builtin.lineinfile: path: /etc/cloud/cloud.cfg regexp: '^ renderers' insertafter: '^ network:' line: " config: disabled" when: nmconnection_eth0_result.changed - name: Configure eth1 ip address ansible.builtin.template: src: nmconnection_eth1.j2 dest: /etc/NetworkManager/system-connections/eth1.nmconnection owner: root group: root mode: 0700 when: ansible_local['static']['general']['ipaddr_eth1'] is defined and ansible_local['static']['general']['ipaddr_eth1'] != "" register: nmconnection_eth1_result - name: Reload eth1 configuration command: | nmcli connection reload nmcli connection up eth1 when: nmconnection_eth1_result.changed # - name: Display all variables/facts known for a host # debug: # var: hostvars[inventory_hostname] # tags: debug_info - name: Install the packages when os is rhel ansible.builtin.dnf: name: "{{ item.name }}" state: "{{ item.state }}" loop: "{{ packages_rhel }}" when: ansible_os_family == "RedHat" - name: Install the packages when os is debian ansible.builtin.apt: name: "{{ item.name }}" state: "{{ item.state }}" loop: "{{ packages_debian }}" when: ansible_os_family == "Debian" or ansible_os_family == "Ubuntu" - name: Enable atop is enabled and started ansible.builtin.systemd_service: name: atop enabled: true state: started - name: Disable SELinux persist ansible.builtin.selinux: state: permissive policy: targeted - name: Set SELinux in permissive mode at runtime command: setenforce 0 - name: kernel parameters ansible.builtin.sysctl: name: "{{ item.name }}" value: "{{ item.value }}" loop: "{{ kernel_parameters }}" - name: Update grubby command: grubby --update-kernel=ALL --args="net.ifnames=0 biosdevname=0 crashkernel=256M intel_idle.max_cstate=0 processor.max_cstate=1 idle=poll console=tty1 ipv6.disable=1 pci=nommconf pcie_aspm=off mitigations=off" when: ansible_os_family == "RedHat" - name: Ensure bash profile history lines number is unlimited ansible.builtin.lineinfile: path: /etc/profile regexp: '^HISTSIZE ' insertafter: '^#HISTSIZE ' line: HISTSIZE=-1 - name: Ensure bash profile history file size is unlimited ansible.builtin.lineinfile: path: /etc/profile regexp: '^HISTFILESIZE ' insertafter: '^#HISTFILESIZE ' line: HISTFILESIZE=-1 become: true ignore_errors: true |
![]() |
16
Kirkcong 7 天前
# tasks file for system configuration
- block: - name: disable SWAP (Kubeadm requirement) shell: | swapoff -a - name: disable SWAP in fstab (Kubeadm requirement) replace: path: /etc/fstab regexp: '^([^#].*?\sswap\s+sw\s+.*)$' replace: '# \1' - name: create an empty file for the Containerd module copy: content: "" dest: /etc/modules-load.d/containerd.conf force: no - name: configure modules for Containerd blockinfile: path: /etc/modules-load.d/containerd.conf block: | overlay br_netfilter - name: create an empty file for Kubernetes sysctl params copy: content: "" dest: /etc/sysctl.d/99-kubernetes-cri.conf force: no - name: configure sysctl params for Kubernetes lineinfile: path: /etc/sysctl.d/99-kubernetes-cri.conf line: "{{ item }}" with_items: - 'net.bridge.bridge-nf-call-iptables = 1' - 'net.ipv4.ip_forward = 1' - 'net.bridge.bridge-nf-call-ip6tables = 1' - name: apply sysctl params without reboot command: sysctl --system - name: add Docker's dnf repository get_url: url: https://download.docker.com/linux/rhel/docker-ce.repo dest: /etc/yum.repos.d/docker-ce.repo mode: '0644' force: true - name: add Kubernetes' dnf repository yum_repository: name: Kubernetes description: Kubernetes baseurl: https://pkgs.k8s.io/core:/stable:/v{{ ansible_local['static']['kubernetes']['version'] }}/rpm/ gpgkey: https://pkgs.k8s.io/core:/stable:/v{{ ansible_local['static']['kubernetes']['version'] }}/rpm/repodata/repomd.xml.key enabled: true gpgcheck: true state: present - name: install Containerd ansible.builtin.dnf: name: containerd.io state: present - name: create Containerd directory file: path: /etc/containerd state: directory - name: add Containerd configuration shell: /usr/bin/containerd config default > /etc/containerd/config.toml - name: configuring the systemd cgroup driver for Containerd lineinfile: path: /etc/containerd/config.toml regexp: ' SystemdCgroup = false' line: ' SystemdCgroup = true' - name: enable the Containerd service and start it systemd: name: containerd state: restarted enabled: yes daemon-reload: yes - name: install packages dnf: name: - kubelet - kubeadm - kubectl - iproute-tc state: present update_cache: true register: packages - name: download helm script ansible.builtin.get_url: url: https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 dest: /tmp/get-helm-3.sh mode: '0755' force: true - name: install helm ansible.builtin.shell: cmd: /tmp/get-helm-3.sh - name: enable the Kubelet service, and enable it persistently service: name: kubelet enabled: yes - name: load br_netfilter kernel module modprobe: name: br_netfilter state: present - name: set bridge-nf-call-iptables sysctl: name: net.bridge.bridge-nf-call-iptables value: 1 - name: set ip_forward sysctl: name: net.ipv4.ip_forward value: 1 - name: reboot and wait for reboot to complete reboot: when: packages.changed |
![]() |
17
defunct9 7 天前
GCP 和 AWS 可用不到 kubespray ,纯手搓才用得到。这东西也不是啥好东西,唉,要从 aws 搬家,有得忙了。
|
![]() |
18
EyebrowsWhite OP @Kirkcong #13 我现在也在把个人服务器迁移为用 ansible 管理,如果是服务器初始化、加固、设置自动化备份之类的重复性任务是方便的,但是比如部署个 vaultwarden 啥的单个服务,由于这种服务我只会部署一个,所以感觉写个 playbook 反而不如直接上去敲命令。不过这只是目前的感受,可能随着服务越来越复杂感受也会变化 :)
|
![]() |
19
EyebrowsWhite OP |
20
w568w 7 天前
ansible 主要问题是太太太慢了,我都搞不明白 Python 怎么能那么慢,五台服务器每次启动任务都要先等个 10 分钟,每个任务执行前后都要卡个四五秒,也不知道在初始化什么东西…… 网络连接肯定没问题的,ssh 也是秒连,服务器本身性能肯定足够
后来换 pyinfra 了,体验还可以: https://pyinfra.com/ |
![]() |
21
Kirkcong 7 天前
@EyebrowsWhite #18 对于你的这个例子,playbook 写的应该是 docker compose 的安装(如果是 docker 的话)以及 wget 你的 docker compose yml 从 git 。
我个人有很多的 vps,不同用途,但基础配置通用,至于个性化的配置写入 ansible 是因为机器由于各种原因需要升级、重建,比如从一个服务商切换到另一个,又或者机器弄乱了,也可能是为了升级。 如果你的机器不多,没有重建的需求,可以只写通用的配置,比如关闭 selinux,关掉 firewalld,禁止 ipv6,创建用户,加 key,对于单个服务,如果是你的生产环境,那么要做好备份。 |
![]() |
22
EyebrowsWhite OP ![]() @Kirkcong #15 是这样的,我自己也写了一个 bootstrap 的 role ,用来初始化服务器,和你这个很类似,创建管理员用户、安装基础包、加固 SSH 、修改 dotfiles 等等,确实是用起来相当舒服
|
![]() |
23
EyebrowsWhite OP @Kirkcong #21 你这么说的话倒确实是,我没考虑到服务器到期更换这一点,我目前 netcup 稳如老狗,感觉它不倒我不换 haha
|
24
taberu 7 天前 via Android
看看我的 homelab ,基于 ansible 的自动 k8s 环境部署和配置。然后用 jsonnet 为何 k8s 的配置。
https://github.com/aetherrootr/os-environment |
![]() |
25
Kirkcong 7 天前
@w568w #20 我们几十上百台机器跑一个 playbook 获取 facts 都没你 10 分钟这么久,你这个不正常,debug 一下看看卡哪里了吧,命令后面加上-vvv
|
![]() |
26
EyebrowsWhite OP @w568w 因为默认要 gather facts 吧,不过我个人感觉速度的优先级很低,自动化执行反而是稳定一点会比较重要
|
![]() |
28
defunct9 7 天前
GCP 有直接建的 autopilot ,用这个东西手搓,真是闲的没事干了。
|
30
hervey0424 7 天前 ![]() 管理个破电脑就这么爽了, 要是让你管理几个人那不得飞起来啊
|
![]() |
31
Kirkcong 7 天前
@EyebrowsWhite #23 我最开始是腾讯轻量,后来换到了 aws lightsail, 再然后 hosthatch 黑五时候开了三年的机器,现在转到 ovh dedicate 了。。。
|
![]() |
32
defunct9 7 天前
楼上热火朝天的,ansible 的变量有几个级别?这是我被面试的时候问到的问题。
|
33
salmon5 7 天前
看来你这个前端挺闲的
|
![]() |
35
EyebrowsWhite OP @Kirkcong #31 牛的,下一步是 bare mental 哈哈哈
|
36
taberu 7 天前 via Android
@defunct9 啊?这是面 devops 的岗位吗?问一般的开发感觉有点离谱了。我觉得 ansible 能靠 Google/ai 写出来能跑的配置就行(:
|
![]() |
37
EyebrowsWhite OP @EyebrowsWhite #35 typo mental -> metal
|
![]() |
38
EyebrowsWhite OP @defunct9 #32 按优先级 roles/defaults 然后 all_vars, group_vars, host_vars, roles/vars, playbook 中的 vars
似乎是这样的,我也不太确定 |
39
w568w 7 天前 ![]() @Kirkcong 嗯,我也觉得奇怪,我准确描述一下现象:是忽快忽慢,有时几秒就 gather 完,有时每台都卡几分钟,甚至直接 connection timeout (而这时我自己连接 ssh 一直是稳定、速度正常的)。debug 不太方便做,所有 infra 都迁移出 ansible 了,现在想连还要重配 inventory ,比较麻烦
@EyebrowsWhite 是的。但调试 ansible playbooks 的时候,肯定不希望每试一个参数都花几分钟时间吧 --- 我也补充下安利 pyinfra 的优点: 1. 纯 python 作为配置,不需要学奇怪的 yaml 脚本和模板语法,简单的管理完全可以单文件 all-in-one 。现在感觉 ansible 这一套复杂的目录结构只会导致配置文件碎片化,降低可维护性 2. 速度快,前面提过了,不说了 3. two-pass 执行,部署任务时可以先快速给你列出哪些任务需要执行、哪些任务可直接 skip ,然后根据实际情况选择执行 4. 文档简单,API 比 ansible 简易太多 缺点: 1. 没有 ansible 那么庞大的 roles 库,大部分复杂配置需要自己手敲(不过也敲不了几行,而且都是 Python ,很容易组织起来复用) |
![]() |
40
Kirkcong 7 天前
@EyebrowsWhite #35 dedicate 就已经是 baremetal 了,而且,我还有一台 colo 放联通机房了
|
![]() |
41
EyebrowsWhite OP @taberu #24 我发现你居然用的 GL.iNet ,我也有一台,不过是 MT3000
|
![]() |
42
DUNAI 7 天前 via Android
@hervey0424 笑死我了
|
![]() |
43
guanzhangzhang 7 天前
@EyebrowsWhite #11 很多地方都可以用到 jinja ,tpl 里是尝试,但是例如 role 和 tasks 里右侧的值地方,基本都可以用 jinja 做,有这个意识后可以写很多动态 task 和复用 role 。我这内部屎山就是很多模板和逻辑之前的人不会 jinja ,写得老长冗余和维护好多模板文件
![]() |
44
taberu 7 天前 via Android
@EyebrowsWhite 偷懒不想自己刷 openwrt 就买现成的了,我的实践下来发现,gl 的镜像缺少 bash ,有时候 Python 似乎也有问题。想要跟 ansible 配合得比较好,还得自己找机器刷 openwrt 。所以我现在都是自己 build 镜像( gl 有个仓库允许你自己定义镜像),就不需要 ansible 刷系统环境了
|
![]() |
45
coefu 7 天前
出错的时候,也挺爽的。🤣
|
46
justdoit123 7 天前
@w568w 听起来不错,感谢分享!我个人真的讨厌 DSL ,用个工具就要学一个 DSL 。
所以在学习 Terraform 的时候,我就选择了 Pulumi 。像编程一样,写资源配置。 之前学 ansible ,怎么就没深入探索一下有没有其它方案。 |
47
longmeier90 7 天前
c 超过 100 台你就不要用了太慢,你可以用 saltstack
|
48
chenqh 7 天前
@longmeier90 100 台,好大的梦
|
![]() |
49
bruce0 7 天前
借楼问一下 ansible 有什么好用的 管理后台吗, 我现在都是 在命令行里 用 shell 脚本 调用 play-book🤣
|
![]() |
50
wandehul 7 天前
上规模了,100 台以上就太慢了, 等不了。 还是 saltstack 比较快, 已经开始转 saltstack 了。
|
![]() |
51
EyebrowsWhite OP |
52
php81 7 天前
没有 docker 之前还常用 ansible ,但是现在自己的项目就 docker-compose yaml
|
53
anjing01 7 天前
最早用 puppet ,每个机器要装 Agent ,然后根据机器类别维护好列表就行;现在懒得搞,直接 ansible 梭哈;
感觉 Puppet 有个功能比较省事,就是严格自动执行服务端要求,客户端手工修改会被自动纠正(如 crontab/authorized/账户添加删除等) |
54
longmeier90 7 天前
@bruce0 我现在就用 django 当管理后台,内置 ansible 。进行代码发布
|
![]() |
55
liuliancao 6 天前
ansible 有个图形化界面 awx 我一直在用 可以配置一些定时 资产也能管理起来 还是不错的
|
![]() |
56
shiny 6 天前
kamal 用来部署很爽,也没有 k8s 这么麻烦
|
![]() |
57
pckillers 6 天前
才 10 台,一般 MobaXterm 用 MultiExec 并行执行命令就能完成大部分临时需求了。 也就标准的部署操作会额外去维护 ansible playbook 。 后来用 k8s 了,ansible 也就用不到了。
|
![]() |
58
EyebrowsWhite OP |
![]() |
59
EyebrowsWhite OP @shiny 看了眼还是 DHH 的项目,可惜我不会 ruby
|
![]() |
60
EyebrowsWhite OP @anjing01 这个自动纠正怎么理解,是手动修改之后 agent 自动改回来吗,还是要等到下一次任务执行
|
![]() |
61
shiny 6 天前
@EyebrowsWhite 不会 ruby 也能用,只是配置个 yaml 。补上了 docker compose 缺失的功能,相当好用
|
![]() |
62
williamherry 6 天前
好多年前用过 chef , 不知道和这个比咋样
|
63
ebi5oowiiy1llo 6 天前 via Android
10 来台机器还是 polysh 比较舒服吧,ansible 虽然跑起来看着爽,但写起来就很难受了,特别是用得不多的时候得来来回回去查它那一坨文档就更难受了,调试也不太行
|
64
hancai2 6 天前
我觉得一般好用吧,playbook 写起来费时费力,还不好调试。 不过现在有了 AI 倒是舒服了不少。
不过想吐槽一下各种 DSL , jnpl pipline helm 模板 等等, 学起来费时费力,工具被淘汰,白学! |
![]() |
65
EyebrowsWhite OP @ebi5oowiiy1llo #63
@hancai2 #64 如果是纯手写,确实写起来会难受很多,但是有了 AI 配合就很流畅了。debug 确实是一个问题,目前我个人用着玩感受还好,真要是规模大了,应该还是要上 Ansible Molecule 这类的测试框架,把流程规范下来的。 关于 DSL ,我个人觉得,不好的地方在于写的时候需要记忆特定规则,好的地方是阅读起来很舒服,一目了然,有 AI 辅助的情况下,我觉得反而比编程语言要好,人只需要 review 就行 |