10 KiB
Walkthrough
Summary
- Overview
- Pipeline definition
- Pipeline concurrency
- Environment variables
- Triggers
- Steps
Overview
- The project is split between the frontend and the backend
- the backend is a submodule located in api that points towards https://dev.sp-tarkov.com/Rev/spt-items-api.git
- the frontend is a submodule located in frontend that points towards https://dev.sp-tarkov.com/shirito/item-finder-website-frontend.git
- There are two Ansible pipelines
- A docker pipeline drone-docker.yml
- A kubernetes pipeline drone-kubernetes.yml
- All ansible playbook files are located in .ansible
- The documentation is located in documentation
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).