Interrompa uma atualização defeituosa

AnsibleBeginner
Pratique Agora

Introdução

Um novo pacote do Courtyard Sessions tem uma página inicial convincente, mas falta o download para visitantes. Este ambiente independente começa com o site original funcionando nos dois servidores. Melhore a implantação Ansible preparada para restaurar a versão utilizável anterior quando um candidato falhar e parar antes de atualizar outro nó.

Conclua primeiro Atualize um host por vez ou tenha prática equivalente com sua inspeção, delegação, lotes sequenciais, operações copy/file e verificações HTTP completas. Este laboratório ensina a registrar o link real e recuperar com block/rescue. A duração é uma estimativa do autor, não um tempo medido com iniciantes.

Restaure uma versão com falha e pare a implantação

Nesta etapa, você registrará a versão anterior real, recuperará o nó atual após uma verificação malsucedida e interromperá explicitamente o lote seguinte.

Abra a aba Website. O título original é Good things, around the corner. Use The program e Download the program (CSV) para conferir as duas sessões originais. O gateway e os dois servidores SSH são independentes do laboratório anterior; não precisam de arquivos nem processos anteriores.

Mude para a aba Controller, que começa em /home/labex/project. Os arquivos preparados inspect.yml e rollout.yml são as ferramentas do laboratório anterior. Leia o pacote selecionado e o estado atual:

cat group_vars/all.yml
ls packages/courtyard-incomplete
ansible-playbook inspect.yml

release_id seleciona courtyard-incomplete. Sua página inicial e identidade existem, mas não há schedule.csv. Os dois servidores reais ainda informam courtyard-preview. Preserve os bytes de todos os pacotes: acrescentar um CSV ao candidato esconderia o defeito, em vez de praticar a recuperação. Ainda não execute a implantação sem proteção.

Um block agrupa tarefas que podem falhar; suas tarefas rescue são executadas depois que uma tarefa do bloco falha normalmente. Registre current antes do bloco com stat, que lê metadados do sistema de arquivos. follow: false lê o próprio link, e não o diretório de destino. O valor salvo previous.stat.lnk_source é o destino anterior real: a recuperação restaura o que estava em execução, em vez de supor um diretório fixo.

A recuperação deve restaurar o link, solicitar a página e o CSV completos restaurados e compará-los com o pacote anterior. O filtro basename extrai o nome do diretório de versão do destino salvo para que as comparações existentes com lookup('file', ...) leiam o pacote local correspondente. Só um nó restaurado e saudável é recolocado. Se algum recurso restaurado estiver ausente ou seu conteúdo estiver errado, essa tarefa de rescue falha e o nó permanece fora; o outro servidor continua atendendo os visitantes.

Um rescue bem-sucedido remove o efeito da falha original nas decisões de tratamento de erros do Ansible. Por isso, any_errors_fatal sozinho não interrompe os lotes posteriores quando a recuperação tem sucesso. Um fail explícito no fim de rescue informa a rejeição e interrompe o lote seguinte. A saída diferente de zero é intencional, embora o site anterior volte a funcionar. YAML inválido e hosts SSH inacessíveis não acionam esse mecanismo de rescue; ele não é uma garantia geral de reversão.

Substitua rollout.yml por esta versão completa. cat > substitui apenas este playbook do aluno; o delimitador entre aspas preserva as expressões do Ansible. Mantenha os espaços mostrados:

cat > rollout.yml <<'YAML'
- name: Release one website backend at a time
  hosts: website
  order: sorted
  gather_facts: false
  serial: 1
  any_errors_fatal: true
  tasks:
    - name: Remember the actual previous release link
      ansible.builtin.stat:
        path: "{{ release_root }}/current"
        follow: false
      register: previous
    - name: Update this backend or recover it
      block:
        - name: Drain this backend from the pool
          ansible.builtin.uri:
            url: "{{ pool_api }}/pool"
            method: POST
            body_format: json
            body:
              node: "{{ inventory_hostname }}"
              enabled: false
          delegate_to: controller
        - name: Create this release directory
          ansible.builtin.file:
            path: "{{ release_root }}/releases/{{ release_id }}"
            state: directory
            mode: '0755'
        - name: Copy the selected package over SSH
          ansible.builtin.copy:
            src: "{{ package_root }}/{{ release_id }}/"
            dest: "{{ release_root }}/releases/{{ release_id }}/"
            mode: '0644'
        - name: Activate the selected release
          ansible.builtin.file:
            src: "{{ release_root }}/releases/{{ release_id }}"
            dest: "{{ release_root }}/current"
            state: link
        - name: Read the real candidate homepage
          ansible.builtin.uri:
            url: "http://{{ hostvars[inventory_hostname].ansible_host }}:{{ backend_port }}/"
            return_content: true
          delegate_to: controller
          register: homepage
        - name: Require the complete candidate homepage
          ansible.builtin.assert:
            that: homepage.content == lookup('file', package_root ~ '/' ~ release_id ~ '/index.html', rstrip=False)
        - name: Read the real candidate download
          ansible.builtin.uri:
            url: "http://{{ hostvars[inventory_hostname].ansible_host }}:{{ backend_port }}/schedule.csv"
            return_content: true
          delegate_to: controller
          register: download
        - name: Require the complete approved program
          ansible.builtin.assert:
            that: download.content == lookup('file', package_root ~ '/' ~ approved_release ~ '/schedule.csv', rstrip=False)
        - name: Rejoin only after both business checks
          ansible.builtin.uri:
            url: "{{ pool_api }}/pool"
            method: POST
            body_format: json
            body:
              node: "{{ inventory_hostname }}"
              enabled: true
          delegate_to: controller
      rescue:
        - name: Restore the previous release link
          ansible.builtin.file:
            src: "{{ previous.stat.lnk_source }}"
            dest: "{{ release_root }}/current"
            state: link
        - name: Read the restored homepage
          ansible.builtin.uri:
            url: "http://{{ hostvars[inventory_hostname].ansible_host }}:{{ backend_port }}/"
            return_content: true
          delegate_to: controller
          register: restored_home
        - name: Require the complete previous homepage
          ansible.builtin.assert:
            that: restored_home.content == lookup('file', package_root ~ '/' ~ (previous.stat.lnk_source | basename) ~ '/index.html', rstrip=False)
        - name: Read the restored download
          ansible.builtin.uri:
            url: "http://{{ hostvars[inventory_hostname].ansible_host }}:{{ backend_port }}/schedule.csv"
            return_content: true
          delegate_to: controller
          register: restored_download
        - name: Require the complete previous program
          ansible.builtin.assert:
            that: restored_download.content == lookup('file', package_root ~ '/' ~ (previous.stat.lnk_source | basename) ~ '/schedule.csv', rstrip=False)
        - name: Rejoin only after both restoration checks
          ansible.builtin.uri:
            url: "{{ pool_api }}/pool"
            method: POST
            body_format: json
            body:
              node: "{{ inventory_hostname }}"
              enabled: true
          delegate_to: controller
        - name: Stop subsequent batches after recovery
          ansible.builtin.fail:
            msg: Candidate failed; the previous release is healthy again. Stop this rollout.
YAML

Valide a sintaxe antes de alterar qualquer servidor:

ansible-playbook rollout.yml --syntax-check

Depois tente publicar a versão incompleta. Espera-se que este comando falhe após recuperar o site:

ansible-playbook rollout.yml

Leia imediatamente o estado de saída. $? contém o estado de saída do comando anterior, e echo o imprime. Outro comando substituiria esse valor guardado pelo shell:

echo $?

Espere um estado diferente de zero, normalmente 2. A verificação da página nova tem sucesso; o download do candidato retorna HTTP 404; a página e o CSV restaurados passam; depois Stop subsequent batches after recovery falha intencionalmente. HTTP 404 identifica o download ausente. A conexão SSH continua disponível para a recuperação. web2 não deve entrar nas tarefas de publicação.

Execute novamente a ferramenta de observação:

ansible-playbook inspect.yml

Ambos os servidores devem mostrar courtyard-preview e permanecer ativos. Mude para Website, recarregue, entre em The program, baixe novamente o CSV e confira que as duas sessões originais continuam disponíveis. Plan a visit deve continuar mostrando as informações de acessibilidade.

O site restaurado continua oferecendo as duas sessões originais e o download completo.

Site restaurado do Courtyard Sessions com sua programação original

Para um erro comum de YAML ou nome de arquivo, use ls, corrija o playbook inteiro e repita a verificação sintática. Se uma edição anterior alterou o link antes de a recuperação funcionar, primeiro salve o playbook correto acima. Você pode usar a mesma implantação saudável já aprendida para restaurar o pacote original conhecido, selecionando-o tanto como versão quanto como programação esperada. As aspas mantêm essas duas atribuições em um único argumento --extra-vars:

ansible-playbook rollout.yml --extra-vars "release_id=courtyard-preview approved_release=courtyard-preview"

Esse comando de restauração deve ter sucesso. Confirme os dois nós com inspect.yml e depois repita o candidato incompleto com o comando original ansible-playbook rollout.yml para demonstrar a falha e a recuperação exigidas. Não redefina a VM nem reescreva o candidato. Mantenha o playbook reutilizável: as solicitações do pool devem usar o pool_api fornecido, os caminhos devem usar release_root e package_root, e as tarefas devem usar os módulos diretos mostrados.

Resumo

Você recuperou o site anterior real após uma falha verdadeira de download ausente. Ambas as verificações de restauração controlam a reinclusão, e uma falha explícita interrompe os próximos lotes do Ansible mesmo quando rescue termina com sucesso.