background

Ad-hoc, through the execution of one line of command, can achieve simple file management, software package management, service management, etc. But if you want to perform a task multiple times, or multiple tasks at once, ad-hoc is a bit cumbersome and overwhelming, and that’s where the Playbook comes in.

Written in YML syntax, the Playbook is legible and readable enough to be easily understood as a programming language (with its own concepts of variables, branches, loops, listeners). A Playbook can contain a set of automated tasks, including the following:

- hosts: group                     [Host or host group]
  tasks:                           [Mission in the script]
    - name:                        [Input module options]
      module:                      [Enter the module to execute]
        module_options-1: value    [Input module options]
        module_options-2: value
        .
        module_options-N: value
Copy the code

Note:

  1. performad-hocCommand, passansibileProgram running;
  2. performplaybookScript, approvedansibile-playbookProgram running;

Host listing

The host list configuration is the same as in the previous Ansible paper 01: Recognize Ansible and group it (1 control server, 3 Web services, 1 database service, 1 cache service).

The default configuration file for Ansible is /etc/ansible/hosts
[root@ecs-kunpeng-0001 ~]# vim /etc/ansible/hosts
# Configure the following
[controller]
192.168.0.6
[web]
192.168.0.53
192.168.0.39
192.168.0.46
[db]
192.168.0.235
[cache]
192.168.0.166
Copy the code

ansibile-playbook

  • Syntax of the ansibile-playbook command:

    Ansible-playbook

  • Check the script for grammatical errors

    Ansible-playbook –syntax-check

Note: Typically a special directory is created for playbook playbooks.

Playbook basic example: Install JDK

  • playbookThe source code
- hosts: cache
  tasks:
    Create an installation directory on the target host group
    - name: mkdir jdk directory
      file: 
        path: /opt
        state: directory
        mode: 755
    # Transfer file from local to remote host group and decompress
    - name: copy and unzip jdk 
      unarchive: 
        src: /opt/software/jdk-8u281-linux-aarch64.tar.gz
        dest: /opt
    Set environment variables
    - name: set env 
      lineinfile: dest=/etc/profile insertafter="{{item.position}}" line="{{item.value}}" state=present
      with_items:
        - {position: EOF.value: "Export JAVA_HOME = / opt/jdk1.8.0 _281"}
        - {position: EOF.value: "export PATH=$JAVA_HOME/bin:$PATH"}
    # grant permission
    - name: chmod bin
      file: 
        dest: / opt/jdk1.8.0 _281 / bin
        mode: 755
        recurse: yes
    # refresh configuration
    - name: refresh env
      shell: source /etc/profile
Copy the code
  • playbookperform
# check the syntax (if there is no error message)
[root@ecs-kunpeng-0001 ~]# ansible-playbook /opt/playbook/install-jdk.yml --syntax-check

playbook: /opt/playbook/install-jdk.yml

# to perform the playbook
[root@ecs-kunpeng-0001 ~]# ansible-playbook /opt/playbook/install-jdk.ymlPLAY [cache] ******************************************************************************************************************* TASK  [Gathering Facts] ********************************************************************************************************* ok: [192.168.0.166] TASK [mkdir JDK directory] ***************************************************************************************************** changed: [192.168.0.166] [copy and unzip JDK] ****************************************************************************************************** changed: [192.168.0.166] TASK [setenv] ***************************************************************************************************************** Changed: [192.168.0.166] = > (item = {'position': 'EOF'.'value': 'export JAVA_HOME = / opt/jdk1.8.0 _281'})
changed: [192.168.0.166] => (item={'position': 'EOF'.'value': 'export PATH=$JAVA_HOME/bin:$PATH'}) TASK [chmod bin] *************************************************************************************************************** changed: [192.168.0.166] TASK [refresh env] ************************************************************************************************************* changed: [192.168.0.166] PLAY RECAP * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 5. Failed =0 skipped=0 bailed =0 rescued=0 ignored=0Copy the code

Playbook advanced instance: Deploying the SpringBoot service

The following script contains the basic Playbook syntax: variables, conditions, loops, and so on. Of course, to demonstrate the effect of Playbook, instead of using CI tools such as Jenkins to increase the complexity of understanding, the jar packages to be deployed are manually placed in a directory on the controller.

  • playbookcode
- hosts: controller Define the host to run on
  vars: # set variable
    deploy_dir: /opt/deploy
    jar_dir_name: registry

  remote_user: root
  gather_facts: no
  tasks:
    Get the filename locally packaged
    - name: Get local file name
      local_action: shell ls {{ deploy_dir }}/ {{ jar_dir_name }}/*.jar
      register: file_name

    Create a target directory
    - name: create target directory {{ deploy_dir }}/ {{ jar_dir_name }}
      file:
        path: "{{ deploy_dir }}/{{ jar_dir_name }}"
        state: directory
      when: file_name.stdout ! = ""

    Upload jar package to server
    - name: Upload jar file to server {{ file_name.stdout }}
      copy:
        src: "{{ file_name.stdout }}"
        dest: "{{ deploy_dir }}/{{ jar_dir_name }}"
      when: file_name.stdout ! = ""

    Get the PID of the last JAR package run
    - name: Get pid of service
      shell: "ps -ef | grep -v grep | grep {{ jar_dir_name }}- | awk '{print $2}'"
      register: running_processes

    # Send a stop signal
    - name: Kill running processes {{ running_processes.stdout_lines }}
      shell: "kill {{ item }}"
      with_items: "{{ running_processes.stdout_lines }}"

    Wait 60 seconds to confirm whether all the pids obtained stop running
    - wait_for:
        path: "/proc/{{ item }}/status"
        state: absent
        timeout: 60
      with_items: "{{ running_processes.stdout_lines }}"
      ignore_errors: yes
      register: killed_processes

    # Force kill, not stop running process
    - name: Force kill stuck processes
      shell: "kill -9 {{ item }}"
      with_items: "{{ killed_processes.results | select('failed') | map(attribute='item') | list }}"

    Start a new JAR package
    - name: Start service {{ file_name.stdout }}
      shell: "nohup java -jar {{ file_name.stdout }} --spring.profiles.active=kp &> {{ deploy_dir }}/{{ jar_dir_name }}/nohup.out &"
Copy the code
  • playbookperform
# check syntax
[root@ecs-kunpeng-0001 ~]# ansible-playbook /opt/playbook/deploy-springboot.yml --syntax-check

playbook: /opt/playbook/deploy-springboot.yml

Deploy a SpringBoot, Eureka based registry application, which involves variable passing parameters
[root@ecs-kunpeng-0001 ~]# ansible-playbook /opt/playbook/deploy-springboot.yml -e "jar_dir_name=registry"

PLAY [controller] **************************************************************************************************************

TASK [Get localfile name] ***************************************************************************************************** changed: [192.168.0.6 -> localhost] TASK [create target directory /opt/deploy/registry] **************************************************************************** ok: [192.168.0.6] TASK [Upload the jar file to the server/opt/deploy/registry registry - 0.0.1 - the SNAPSHOT. Jar] ********************************************** ok: [192.168.0.6] TASK [Get pid of service] ****************************************************************************************************** changed: [192.168.0.6] TASK [Kill running processes ['1828029']] **************************************************************************************
changed: [192.168.0.6] => (item=1828029)

TASK [wait_for] ****************************************************************************************************************
ok: [192.168.0.6] => (item=1828029)

TASK [Force killstuck processes] ********************************************************************************************** TASK [Start service/opt/deploy/registry registry - 0.0.1 - the SNAPSHOT. Jar] ********************************************************** changed: [192.168.0.6] PLAY RECAP * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * B: OK =7 changed=4 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0Copy the code

Reference

  • Docs.ansible.com/ansible/lat…

  • Docs.ansible.com/ansible/2.9…

  • www.jianshu.com/p/d5185bb8c…


If you have any questions or any bugs are found, please feel free to contact me.

Your comments and suggestions are welcome!

This article has participated in the activity of “New person creation Ceremony”, and started the road of digging gold creation together.