Website/items/docs/Walkthrough.md

10 KiB

Walkthrough

Summary

Overview

Pipeline definition

kind: pipeline
type: kubernetes
name: default

The pipeline is defined either as Docker or Kubernetes depending on .drone-docker.yml or .drone-kubernetes.yml. The name is set as default.

Pipeline Concurrency

concurrency:
  limit: 1

The pipeline is set to only one build at a time (every subsequent build with be pending).

Environment variables

environment:
  SPT_ITEMS_PATH: /var/www/html/aki/spt-items-api

Here are the environment variables. They are automatically injected in every step.

Triggers

trigger:
  event:
    - push
    - promote

The pipeline is run on every push and every promote. Since the repository is kind of a trunk, I dont think we need branches policies. Most steps are executed on any push since we want to check that everything builds and is still valid (tests are not added yet). Only the deployment is protected behing the promotion to production.

Steps

Fetch and update submodules

- name: fetch and update submodules to the latest commit
  image: alpine/git
  commands:
  - git submodule init
  - git submodule update --recursive --remote

Executed on every push.
Fetching and updating submodules to the latest commit.

Replace hosts and user variables

- name: replace hosts and user variables
  image: ubuntu:impish
  environment:
    DEPLOY_HOSTNAME:
      from_secret: deploy_hostname
    SPT_ITEMS_HOSTNAME:
      from_secret: spt_items_hostname
    DEPLOYMENT_USER:
      from_secret: deploy_username
  commands:
    -  sed -i 's/{{ SPT_ITEMS_HOSTNAME }}/'"$SPT_ITEMS_HOSTNAME"'/g' ./frontend/.env
    -  sed -i 's/{{ DEPLOY_HOSTNAME }}/'"$DEPLOY_HOSTNAME"'/g' ./.ansible/inventory
    -  sed -i 's/{{ DEPLOYMENT_USER }}/'"$DEPLOYMENT_USER"'/g' ./.ansible/inventory

Executed on every push.
The following environment variables are injected using Drone secrets: * SPT_ITEMS_HOSTNAME is used by the frontend to call the backend. * DEPLOY_HOSTNAME is used by Ansible to connect to the remote server via SSH. * DEPLOYMENT_USER is used by Ansible to connect to the remote server via SSH. * all environment variables at the pipeline level (see Environment variables) Using sed makes temporary changes in the container/pod instead of commiting secrets in the repo in plain text.
The changes are never pushed and are discarded when the container/pod is terminated.

Build frontend

- name: build frontend
  image: node:lts-alpine3.14
  commands:
    - node -v
    - npm -v
    - yarn --version
    - yarn --cwd ./frontend install
    - yarn --cwd ./frontend build --pure-lockfile
    - rm -rf ./api/public/static/*
    - mv ./frontend/build/* ./api/public
    - rm ./api/public/index.html

Executed on every push.
Since the PHP backend serves the ReactJS frontend, the former is built and moved in the latter. Notes: * yarn --cwd <path> <command> executes the command in the specified file * rm -rf ./api/public/static/* deletes the static files to make sure no old JavaScript files remain * rm ./api/public/index.html ReactJS is bundled with a index.html. It is discarded to use instead.

Check ansible syntax

- name: check ansible syntax
  image: plugins/ansible:3
  settings:
    playbook: ./.ansible/playbook.yml
    inventory: ./.ansible/inventory
    galaxy: ./.ansible/requirements.yml
    syntax_check: true

Executed on every push.
Check the Ansible syntax in playbook.yml, inventory and requirements.yml. The check is executed on every push since we want to detect any error before validating the build using the promotion.

Apply ansible playbook

- name: apply ansible playbook
  image: plugins/ansible:3
  settings:
    playbook: ./.ansible/playbook.yml
    inventory: ./.ansible/inventory
    galaxy: ./.ansible/requirements.yml
    private_key:
      from_secret: deploy_ssh_key
  environment:
    DEPLOY_HOSTNAME:
      from_secret: deploy_hostname
    SPT_ITEMS_HOSTNAME:
      from_secret: spt_items_hostname
    DEPLOYMENT_USER:
      from_secret: deploy_username
  when:
    event:
      - promote
    target:
      - production

Executed only on promotion to production.
This step actually deploys to the server.
This step is idempotent.
The following environment variables are injected using Drone secrets: * SPT_ITEMS_HOSTNAME is used by the PHP env file. * DEPLOY_HOSTNAME is used to connect to the remote server via SSH. * DEPLOYMENT_USER is used to connect to the remote server via SSH. * all environment variables at the pipeline level (see Environment variables)

Playbook definition

hosts: host
become_user: root
become: true
become_method: sudo

Uses the host defined in inventory. Remember, the step Replace hosts and user variables already replaced the variables at this point. The playbook will be executed as root user using sudo.

Delete old spt-items-api

- name: Delete spt-items-api before adding everything again
  file:
    state: absent
    path: "{{ lookup('env', 'SPT_ITEMS_PATH') }}"

Since the copy does not override the folder, this step takes care of it.
SPT_ITEMS_PATH is injected thanks to the pipeline level environment variables (see Environment variables)

Copy the project

- name: Copy the project
  copy:
    src: ../api/
    dest: "{{ lookup('env', 'SPT_ITEMS_PATH') }}"

Copies the whole project (frontend and backend) from the api folder into the server.

Copy PHP env file

- name: Copy PHP .env file
  template:
    src: ./templates/.php-env.j2
    dest: "{{ lookup('env', 'SPT_ITEMS_PATH') }}/.env"

Uses Jinja2 to resolve the template for the PHP .env file.
SPT_ITEMS_PATH is injected thanks to the pipeline level environment variables (see Environment variables).
SPT_ITEMS_HOSTNAME is injected in the environments properties (see Apply ansible playbook)

Get JavaScript chunks name

- name: Get Chunk 2 name
  shell:
    cmd: find "{{ lookup('env', 'SPT_ITEMS_PATH') }}" -type f -name "*chunk.js" -printf "%f\n"
  register: find_output

Prepare a find of all JavaScript chunk files for the app.blade.php.j2 template.
SPT_ITEMS_PATH is injected thanks to the pipeline level environment variables (see Environment variables).

Get file names from find output

- name: Get file names from find output
  set_fact:
    chunk_list: "{{ find_output['stdout'].split('\n') }}"

Splits the string containing the list of all JavaScript chunk files for the app.blade.php.j2 template.

Copy app.blade.php file

- name: Copy app.blade.php file
  template:
    src: ./templates/app.blade.php.j2
    dest: "{{ lookup('env', 'SPT_ITEMS_PATH') }}/resources/views/app.blade.php"

Uses Jinja2 to resolve the template for the PHP app.blade.php file.
SPT_ITEMS_PATH is injected thanks to the pipeline level environment variables (see Environment variables).

Download and install composer dependencies

- name: Download and installs all composer libs and dependencies
  community.general.composer:
    command: install
    working_dir: "{{ lookup('env', 'SPT_ITEMS_PATH') }}"

Reset files permissions

- name: Reset files permissions
  file:
    path: "{{ lookup('env', 'SPT_ITEMS_PATH') }}"
    owner: www-data
    group: www-data
    mode: 0744
    recurse: yes

Permissions 0644: * user: read/write/execute * group: read * other: read www-data is hardcoded here but it should be the standard user for Apache and Nginx.
SPT_ITEMS_PATH is injected thanks to the pipeline level environment variables (see Environment variables).