Ответ
В современной инфраструктуре я не обновляю серверы по отдельности, а работаю с ними как со временным, заменяемым скотчем (cattle, not pets). Основной инструмент — инфраструктура как код (IaC) и оркестрация.
1. Подход «Immutable Infrastructure»: Вместо обновления пакетов на работающем сервере я создаю новый образ системы с помощью Packer. В скрипте provisioning указываю все необходимые пакеты и их версии.
source "amazon-ebs" "ubuntu" {
ami_name = "my-app-base-{{timestamp}}"
instance_type = "t3.micro"
source_ami = "ami-0c55b159cbfafe1f0" # Ubuntu 20.04 LTS
}
build {
sources = ["source.amazon-ebs.ubuntu"]
provisioner "shell" {
script = "scripts/install_dependencies.sh"
}
}
Затем с помощью Terraform разворачиваю автоскейлинг-группу (ASG) в AWS или аналоги в другом облаке, используя этот новый AMI. Старые инстансы постепенно заменяются новыми.
2. Для Kubernetes: Если сервис работает в Kubernetes, обновление происходит через изменение манифеста Deployment.
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25% # Не более 25% подов могут быть недоступны
maxSurge: 1 # Можно создать 1 дополнительный под во время обновления
template:
spec:
containers:
- name: app
image: my-registry/app:v2.0.0 # Меняю версию образа
Kubernetes сам выполнит rolling update: создаст поды с новой версией, дождется их готовности (readiness probe) и затем удалит старые.
3. Для традиционных серверов (если immutable подход невозможен): Использую Ansible для идемпотентного управления конфигурацией. Плейбук описывает желаемое состояние системы.
- name: Update system packages
hosts: webservers
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Upgrade all packages
apt:
upgrade: dist
autoremove: yes
- name: Reboot if required
reboot:
msg: "Reboot triggered by Ansible for kernel update"
reboot_timeout: 300
Запускаю его в режиме rolling update, обрабатывая серверы по группам, чтобы обеспечить доступность сервиса. Все изменения предварительно тестирую на staging-окружении.