Ansible 用起来好爽😄
本人只是个前端,很早之前就听说过 ansible, terraform 这类运维工具,一直没机会上手玩一下,上个月借着 GCP 刚开通的 300 刀额度业余时间鼓捣了一下,到现在一个多月了,发现真的是个神器啊,特别是如果有个十来台服务器一起执行 playbook 的时候,有种莫名的爽感😄
一直用一直爽。但 k8s 比这个爽。
是啊是啊,超爽的,我们 1000+台机器,全靠 ansible
问题是,好像个人使用没什么使用场景吧?
等玩腻了 ansible 就折腾 k8s ,其实之前尝试上手过,但是如果不用 GKE 之类的基础设施就太复杂了,而如果用的话又没那种感觉 :) 毕竟我不是专业运维,没有业务需求和压力。很巧的是,我在用一个 ansible wireguard role 的时候看到作者就是纯自己搭建的 k8s ,打算后面跟着他的 blog( www.tauceti.blog/)搞一下
链接有点问题 www.tauceti.blog/posts/kubernetes-the-not-so-hard-way-with-ansible-the-basics/
有个疑问,我想知道你们最多会在多少台机器执行任务啊,如果 1000 台一起执行,控制节点顶得住吗
说实话,没有。我感觉就几台服务器反而会拖慢效率,不如 ssh 上去手敲命令,不过这种工具玩起来就很有趣
#6 看了下监控系统,目前是 1080 台机器。不会同时执行的,我们有不同的 team ,ansible 机器设置了 crontab 错开时间,总共 65 个 team 。倒不是 ansible 机器承受不住,是因为不同 team 配置不同,执行的 role 不同。
至于最多多少台机器执行,这个没法算,我们没有统计每个 team 机器数量。
#3
#6
当你机器配置繁琐的时候,即便数量少,上 ansible 也很轻松。
核心是 jinja2 ,这个熟悉了再会抽配置,就熟练了,很多人都只基础的文件拷贝执行命令啥的
kubespray 是个好东西,正在用它建新集群,参数多多啊。
奥奥,感谢解答,我们使用场景不同,我就一个人玩,和你们团队生产用毕竟还是有很大差距
结合 AI 的话学习起来很快,jinja2 基础用法很简单,就是那些高级的功能比如 Custom Filters 啥的感觉复杂些
看起来很强啊,教程还是用的 GCP ,那我不得不试一试了
#11 我个人的机器也在用 ansible ,包括 k8s 节点的创建,vps 的一些基础配置,比如加 key,创建用户,nfs 挂载,hostname,软件包的安装,有 ansible 会方便很多
作为一个 SRE ,我没怎么用过哈哈哈
---
# 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: Ensure group "admin" exists
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: Create directory for ansible custom facts
- 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'['hostname'] }}"
when: ansible_local'static'['hostname'] is defined and ansible_local'static'['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'['ipaddr_eth1'] is defined and ansible_local'static'['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# tasks file for system configuration
- name: Re-read facts after adding custom fact
block:
- name: disable SWAP (Kubeadm requirement)
shell: |
swapoff -a - name: disable SWAP in fstab (Kubeadm requirement)
replace:
path: /etc/fstab
regexp: '^(1.?\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: 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: pkgs.k8s.io/core:/stable:/v{{ ansible_local'static'['version'] }}/rpm/
gpgkey: pkgs.k8s.io/core:/stable:/v{{ ansible_local'static'['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: 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
GCP 和 AWS 可用不到 kubespray ,纯手搓才用得到。这东西也不是啥好东西,唉,要从 aws 搬家,有得忙了。
#13 我现在也在把个人服务器迁移为用 ansible 管理,如果是服务器初始化、加固、设置自动化备份之类的重复性任务是方便的,但是比如部署个 vaultwarden 啥的单个服务,由于这种服务我只会部署一个,所以感觉写个 playbook 反而不如直接上去敲命令。不过这只是目前的感受,可能随着服务越来越复杂感受也会变化 :)
#17 我看这里官方教程用的就是 GCP , github.com/kubernetes-sigs/kubespray/blob/master/docs/getting_started/setting-up-your-first-cluster.md
ansible 主要问题是太太太慢了,我都搞不明白 Python 怎么能那么慢,五台服务器每次启动任务都要先等个 10 分钟,每个任务执行前后都要卡个四五秒,也不知道在初始化什么东西…… 网络连接肯定没问题的,ssh 也是秒连,服务器本身性能肯定足够
- name: disable SWAP (Kubeadm requirement)
后来换 pyinfra 了,体验还可以: pyinfra.com/
#18 对于你的这个例子,playbook 写的应该是 docker compose 的安装(如果是 docker 的话)以及 wget 你的 docker compose yml 从 git 。
我个人有很多的 vps,不同用途,但基础配置通用,至于个性化的配置写入 ansible 是因为机器由于各种原因需要升级、重建,比如从一个服务商切换到另一个,又或者机器弄乱了,也可能是为了升级。
如果你的机器不多,没有重建的需求,可以只写通用的配置,比如关闭 selinux,关掉 firewalld,禁止 ipv6,创建用户,加 key,对于单个服务,如果是你的生产环境,那么要做好备份。
#15 是这样的,我自己也写了一个 bootstrap 的 role ,用来初始化服务器,和你这个很类似,创建管理员用户、安装基础包、加固 SSH 、修改 dotfiles 等等,确实是用起来相当舒服
#21 你这么说的话倒确实是,我没考虑到服务器到期更换这一点,我目前 netcup 稳如老狗,感觉它不倒我不换 haha
看看我的 homelab ,基于 ansible 的自动 k8s 环境部署和配置。然后用 jsonnet 为何 k8s 的配置。
github.com/aetherrootr/os-environment
#20 我们几十上百台机器跑一个 playbook 获取 facts 都没你 10 分钟这么久,你这个不正常,debug 一下看看卡哪里了吧,命令后面加上-vvv
因为默认要 gather facts 吧,不过我个人感觉速度的优先级很低,自动化执行反而是稳定一点会比较重要
#24 好巧,我也是用 haproxy,不过我是两层,外部 haproxy 给到内部 haproxy
GCP 有直接建的 autopilot ,用这个东西手搓,真是闲的没事干了。
#28 需求不一样,autopilot 不满足
管理个破电脑就这么爽了, 要是让你管理几个人那不得飞起来啊
#23 我最开始是腾讯轻量,后来换到了 aws lightsail, 再然后 hosthatch 黑五时候开了三年的机器,现在转到 ovh dedicate 了。。。
楼上热火朝天的,ansible 的变量有几个级别?这是我被面试的时候问到的问题。
看来你这个前端挺闲的
集群内部的代理无所谓了,我用的比较传统的 Nginx ,在我的应用场景区别不大。
#31 牛的,下一步是 bare mental 哈哈哈
啊?这是面 devops 的岗位吗?问一般的开发感觉有点离谱了。我觉得 ansible 能靠 Google/ai 写出来能跑的配置就行(:
#35 typo mental -> metal
#32 按优先级 roles/defaults 然后 all_vars, group_vars, host_vars, roles/vars, playbook 中的 vars
似乎是这样的,我也不太确定
嗯,我也觉得奇怪,我准确描述一下现象:是忽快忽慢,有时几秒就 gather 完,有时每台都卡几分钟,甚至直接 connection timeout (而这时我自己连接 ssh 一直是稳定、速度正常的)。debug 不太方便做,所有 infra 都迁移出 ansible 了,现在想连还要重配 inventory ,比较麻烦
是的。但调试 ansible playbooks 的时候,肯定不希望每试一个参数都花几分钟时间吧
我也补充下安利 pyinfra 的优点:
- 纯 python 作为配置,不需要学奇怪的 yaml 脚本和模板语法,简单的管理完全可以单文件 all-in-one 。现在感觉 ansible 这一套复杂的目录结构只会导致配置文件碎片化,降低可维护性
- 速度快,前面提过了,不说了
- two-pass 执行,部署任务时可以先快速给你列出哪些任务需要执行、哪些任务可直接 skip ,然后根据实际情况选择执行
- 文档简单,API 比 ansible 简易太多
缺点:
没有 ansible 那么庞大的 roles 库,大部分复杂配置需要自己手敲(不过也敲不了几行,而且都是 Python ,很容易组织起来复用)
#35 dedicate 就已经是 baremetal 了,而且,我还有一台 colo 放联通机房了
#24 我发现你居然用的 GL.iNet ,我也有一台,不过是 MT3000
- # ↩
如题,昨天试了 11 次,挂梯子、不挂梯子、家庭宽带、手机电信移动热点、中国区,招行 VISA 卡,真实地址信息,都是到了测试扣款成功,最后一步 ABC 理由申请失败 纯粹…
按照官方文档和 README 去配置 cas web management,每个分支都试过去了,没有能正常使用的,总会遇到这样或那样的问题。 看 cas 的 github 还…
第一是今年开发岗哀鸿遍野,裸辞了可能根本没 hc ,第二是在一线也混了挺久,感觉有点累。 想回老家一段时间,父母也可以安排工作,而且家里的房子是崭新的别墅大 house ( …