diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index d6280de..9b32f9a 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -14,6 +14,10 @@ jobs: - name: Checkout code uses: actions/checkout@v3 + # Uv is needed for the deployment lint + - name: Install uv + uses: astral-sh/setup-uv@v5 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 @@ -43,6 +47,10 @@ jobs: docker run --rm intbot make ci/lint docker run --rm intbot make ci/type-check + + - name: Run deployment playbooks lint + run: make lint/deploy + services: postgres: image: postgres:16.4 diff --git a/Makefile b/Makefile index dabbabb..30db2d4 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ CI_RUN=cd intbot && DJANGO_SETTINGS_MODULE="intbot.settings" DJANGO_ENV="ci" # Deployment DEPLOY_CMD=cd deploy && uvx --from "ansible-core" ansible-playbook -i hosts.yml +DEPLOY_LINT_CMD=cd deploy && uvx --from "ansible-lint" ansible-lint # mostly useful for docker and deployment current_git_hash=$(shell git rev-parse HEAD) @@ -149,3 +150,8 @@ deploy/provision: deploy/app: @echo "Deploying version $(V) to a remote server" $(DEPLOY_CMD) playbooks/03_app.yml --extra-vars "app_version=$(V)" + +lint/deploy: + $(DEPLOY_LINT_CMD) playbooks/01_setup.yml + $(DEPLOY_LINT_CMD) playbooks/02_nginx.yml + $(DEPLOY_LINT_CMD) playbooks/03_app.yml diff --git a/deploy/playbooks/01_setup.yml b/deploy/playbooks/01_setup.yml index 4768bf3..bcb0743 100644 --- a/deploy/playbooks/01_setup.yml +++ b/deploy/playbooks/01_setup.yml @@ -1,14 +1,14 @@ - name: Deploy nginx and Let's Encrypt SSL certificate hosts: intbot_setup - become: yes - gather_facts: yes + become: true + gather_facts: true tasks: - name: Install Docker dependencies - apt: + ansible.builtin.apt: name: "{{ package }}" state: present - update_cache: yes + update_cache: true vars: package: - apt-transport-https @@ -21,22 +21,22 @@ - name: Install Docker block: - name: Add Docker GPG key - apt_key: + ansible.builtin.apt_key: url: https://download.docker.com/linux/ubuntu/gpg state: present - name: Add Docker repository - apt_repository: + ansible.builtin.apt_repository: repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_lsb.codename }} stable state: present - name: Install Docker - apt: + ansible.builtin.apt: name: docker-ce state: present - name: Combine non-root users to a single list - set_fact: + ansible.builtin.set_fact: non_root_user_names: ["{{ nginx_user }}", "{{ app_user }}"] - name: Create non-root users @@ -45,10 +45,10 @@ ansible.builtin.user: name: "{{ username }}" shell: "/bin/bash" - generate_ssh_key: yes + generate_ssh_key: true ssh_key_type: ed25519 ssh_key_comment: "{{ username }}@{{ inventory_hostname }}" - create_home: yes + create_home: true loop: "{{ non_root_user_names }}" loop_control: loop_var: username @@ -59,37 +59,37 @@ state: directory owner: "{{ username }}" group: "{{ username }}" + mode: "0755" loop: "{{ non_root_user_names }}" loop_control: loop_var: username - name: Then copy the authorized_keys from root so you can ssh later to the user - copy: + ansible.builtin.copy: src: "/root/.ssh/authorized_keys" dest: "/home/{{ username }}/.ssh/authorized_keys" owner: "{{ username }}" group: "{{ username }}" mode: "0600" - remote_src: "yes" + remote_src: true loop: "{{ non_root_user_names }}" loop_control: loop_var: username - name: Add the non root users (both nginx and app) to docker group - user: + ansible.builtin.user: name: "{{ username }}" groups: docker - append: yes + append: true loop: "{{ non_root_user_names }}" loop_control: loop_var: username - name: Read the deploy public key - slurp: + ansible.builtin.slurp: src: "/home/{{ app_user }}/.ssh/id_ed25519.pub" register: deploy_key - name: Display the public key - debug: + ansible.builtin.debug: msg: "For private repositories, make sure to put this key as deploy key on github: {{ deploy_key.content | b64decode }}" - diff --git a/deploy/playbooks/02_nginx.yml b/deploy/playbooks/02_nginx.yml index d2b4a60..884dbad 100644 --- a/deploy/playbooks/02_nginx.yml +++ b/deploy/playbooks/02_nginx.yml @@ -4,22 +4,28 @@ tasks: - name: Copy nginx configuration file ansible.builtin.template: - src: ../templates/nginx/nginx.conf.j2 + src: nginx/nginx.conf.j2 dest: ./nginx.conf + mode: "0644" - name: Create a server Makefile (for nginx) to manage on-server tasks ansible.builtin.template: - src: ../templates/nginx/Makefile.nginx.j2 + src: nginx/Makefile.nginx.j2 dest: ./Makefile + mode: "0640" - name: Set up docker-compose.yml on the remote server ansible.builtin.template: - src: ../templates/nginx/docker-compose.nginx.yml.j2 + src: nginx/docker-compose.nginx.yml.j2 dest: ./docker-compose.yml + mode: "0640" - name: Make sure the directory structure for certs exist - shell: mkdir -p ./data/certbot/conf + ansible.builtin.file: + path: "/home/{{ ansible_user }}/data/certbot/conf" + state: directory + mode: "0755" - name: Display info at the end - debug: + ansible.builtin.debug: msg: "Go to /home/{{ ansible_user }} and run make certbot/init-staging; then make certbot/upgrade-to-prod" diff --git a/deploy/playbooks/03_app.yml b/deploy/playbooks/03_app.yml index eea96b3..85e1c0a 100644 --- a/deploy/playbooks/03_app.yml +++ b/deploy/playbooks/03_app.yml @@ -3,26 +3,33 @@ tasks: - name: Clone the repository to a specific version (to a temp location) - git: + ansible.builtin.git: repo: "{{ repository_url }}" dest: /tmp/src - accept_hostkey: yes + accept_hostkey: true version: "{{ app_version }}" - name: Build with a given commit hash # This will be stored in local registry, and available as version to docker-compose # where we can just reference correct version - shell: "cd /tmp/src && make docker/build V={{ app_version }}" + ansible.builtin.command: + chdir: /tmp/src + cmd: "/usr/bin/make docker/build V={{ app_version }}" + register: output + changed_when: output.rc != 0 + failed_when: output.rc != 0 - name: Create a server Makefile to manage app tasks ansible.builtin.template: - src: ../templates/app/Makefile.app.j2 + src: app/Makefile.app.j2 dest: ./Makefile + mode: "0640" - name: Set up docker-compose.yml for the app ansible.builtin.template: - src: ../templates/app/docker-compose.app.yml.j2 + src: app/docker-compose.app.yml.j2 dest: ./docker-compose.yml + mode: "0640" - name: Check if the env file exists ansible.builtin.stat: @@ -31,8 +38,9 @@ - name: If env file doesn't exist - copy the example ansible.builtin.copy: - src: ../templates/app/intbot.env.example + src: app/intbot.env.example dest: intbot.env.example + mode: "0644" when: not env_file.stat.exists - name: If the env file doesn't exist - fail with error message @@ -41,10 +49,25 @@ when: not env_file.stat.exists - name: Start docker compose to see if everything is running - shell: "docker compose up -d" + ansible.builtin.command: + chdir: "{{ ansible_user_dir }}" + cmd: "docker compose up -d" + register: output + changed_when: output.rc != 0 + failed_when: output.rc != 0 - name: Migrate on prod - shell: "make prod/migrate" + ansible.builtin.command: + chdir: "{{ ansible_user_dir }}" + cmd: "/usr/bin/make prod/migrate" + register: output + changed_when: output.rc != 0 + failed_when: output.rc != 0 - name: Restart everything and finish - shell: "docker compose up -d" + ansible.builtin.command: + chdir: "{{ ansible_user_dir }}" + cmd: "docker compose up -d" + register: output + changed_when: output.rc != 0 + failed_when: output.rc != 0 diff --git a/deploy/templates/app/.env.example b/deploy/playbooks/templates/app/.env.example similarity index 100% rename from deploy/templates/app/.env.example rename to deploy/playbooks/templates/app/.env.example diff --git a/deploy/templates/app/Makefile.app.j2 b/deploy/playbooks/templates/app/Makefile.app.j2 similarity index 100% rename from deploy/templates/app/Makefile.app.j2 rename to deploy/playbooks/templates/app/Makefile.app.j2 diff --git a/deploy/templates/app/docker-compose.app.yml.j2 b/deploy/playbooks/templates/app/docker-compose.app.yml.j2 similarity index 100% rename from deploy/templates/app/docker-compose.app.yml.j2 rename to deploy/playbooks/templates/app/docker-compose.app.yml.j2 diff --git a/deploy/templates/app/intbot.env.example b/deploy/playbooks/templates/app/intbot.env.example similarity index 100% rename from deploy/templates/app/intbot.env.example rename to deploy/playbooks/templates/app/intbot.env.example diff --git a/deploy/templates/nginx/Makefile.nginx.j2 b/deploy/playbooks/templates/nginx/Makefile.nginx.j2 similarity index 100% rename from deploy/templates/nginx/Makefile.nginx.j2 rename to deploy/playbooks/templates/nginx/Makefile.nginx.j2 diff --git a/deploy/templates/nginx/docker-compose.nginx.yml.j2 b/deploy/playbooks/templates/nginx/docker-compose.nginx.yml.j2 similarity index 100% rename from deploy/templates/nginx/docker-compose.nginx.yml.j2 rename to deploy/playbooks/templates/nginx/docker-compose.nginx.yml.j2 diff --git a/deploy/templates/nginx/nginx.conf.j2 b/deploy/playbooks/templates/nginx/nginx.conf.j2 similarity index 100% rename from deploy/templates/nginx/nginx.conf.j2 rename to deploy/playbooks/templates/nginx/nginx.conf.j2