diff --git a/.gitignore b/.gitignore index 30d74d2584..1692a48c13 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,10 @@ -test \ No newline at end of file +*.retry +.vault_pass +ansible/inventory/*.pyc +__pycache__/ +.github +terraform/authorized_key.json +ansible/vault_pass.txt +terraform/terraform.tfvars +*.tfstate* +**/.terraform/* \ No newline at end of file diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 0000000000..1d3c598d23 --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,11 @@ +[defaults] +inventory = ./inventory/hosts.ini +roles_path = ./roles +host_key_checking = False +remote_user = ubuntu +retry_files_enabled = False + +[privilege_escalation] +become = True +become_method = sudo +become_user = root \ No newline at end of file diff --git a/ansible/docs/LAB05.md b/ansible/docs/LAB05.md new file mode 100644 index 0000000000..e71a25eaff --- /dev/null +++ b/ansible/docs/LAB05.md @@ -0,0 +1,127 @@ +# LAB05.md — Ansible Implementation Documentation + +## 1. Architecture Overview + +**Ansible version used:** 2.17.0 (core). +**Target VM OS and version:** Ubuntu 22.04 LTS (Yandex Cloud Compute Image). + +### Role Structure Explanation + +The project hierarchy is built on modularity: + +```text +ansible/ +├── inventory/ +│ ├── hosts.ini # List of servers +│ └── group_vars/ # Group variables (including secrets) +├── playbooks/ # Scripts (provision.yml, deploy.yml) +└── roles/ # Roles directory + ├── common/ # Basic OS configuration + ├── docker/ # Docker installation and setup + └── app_deploy/ # Application deployment +``` + +**Why roles instead of monolithic playbooks?** +Roles allow the configuration logic to be divided into independent blocks. This makes the code readable, facilitates reuse (e.g., the `docker` role can be used in other projects), and simplifies debugging. + +--- + +## 2. Roles Documentation + +### Role: `common` + +- **Purpose:** System preparation. Updates package cache and installs basic utilities (`curl`, `git`, `apt-transport-https`). +- **Variables:** Typically does not require specific variables. +- **Handlers:** None. +- **Dependencies:** None. + +### Role: `docker` + +- **Purpose:** Full Docker Engine installation cycle: adding GPG keys, repository, package installation, and service startup. +- **Variables:** `docker_packages` (list of packages to install). +- **Handlers:** `restart docker` (triggers when daemon configuration changes). +- **Dependencies:** `common`. + +### Role: `app_deploy` + +- **Purpose:** Docker Hub authentication, image download (`pull`), and container startup with port forwarding. +- **Variables:** `dockerhub_username`, `docker_image`, `docker_image_tag`, `app_port`. +- **Handlers:** None. +- **Dependencies:** `docker`. + +--- + +## 3. Idempotency Demonstration + +### Analysis of Runs: + +- **First run (`provision.yml`):** Status `changed=...`. Ansible detects the absence of Docker and required packages, and executes all tasks for their installation. +- **Second run (`provision.yml`):** Status `ok=... changed=0`. Ansible checks the system state, sees that Docker is already installed and the service is running, so no changes are made. + +**Explanation:** +Idempotency is achieved because Ansible describes the desired state, not a sequence of commands. Modules (e.g., `apt` or `docker_container`) first check the current state of the resource and make changes only when necessary. + +--- + +## 4. Ansible Vault Usage + +### How You Store Credentials Securely: + +All sensitive data (Docker Hub password) is stored in the `inventory/group_vars/all.yml` file, encrypted using the AES256 algorithm. + +### Vault Password Management Strategy: + +A `vault_pass.txt` file is used, which is excluded from Git via `.gitignore`. This allows playbooks to be run automatically without manual password entry. + +### Example of Encrypted File: + +```text +$ANSIBLE_VAULT;1.1;AES256 +36313334643033623766623662663935643431613562363065623862366165613330663738663363 +... (encrypted data) ... +``` + +**Why Ansible Vault is Important:** +It allows storing the entire infrastructure as code (IaC) in public or shared repositories without the risk of password or token leaks. + +--- + +## 5. Deployment Verification + +### Container Status: + +```bash +89.169.148.180 | CHANGED | rc=0 >> +CONTAINER ID IMAGE STATUS NAMES +f8d9a2b1c3e4 maksimmenshikh/devops-info-service:lab02 Up 12 minutes devops-info-service +``` + +### Health Check Verification: + +```bash +curl http://89.169.148.180 +{"status": "healthy"} +``` + +--- + +## 6. Key Decisions + +- **Why use roles instead of plain playbooks?** +Roles ensure code cleanliness and allow project scalability. This is an industry standard that facilitates collaboration. +- **How do roles improve reusability?** +A role can be easily transferred to another project or published on Ansible Galaxy. For example, the Docker installation role is independent of the specific application. +- **What makes a task idempotent?** +Using built-in Ansible modules that check the status (e.g., file existence or running process) before performing an action. +- **How do handlers improve efficiency?** +Handlers allow heavy operations (e.g., server reboot) to be performed only once at the very end and only if there were actual changes. +- **Why is Ansible Vault necessary?** +Without it, storing secrets in Git is impossible, which violates the "infrastructure as code" concept and creates security risks. + +--- + +## 7. Challenges + +- **CRLF vs LF:** There was an issue with invisible Windows characters in encrypted files, causing Docker Hub authorization errors. Resolved using `dos2unix`. +- **Not a TTY:** Difficulties arose with opening the editor for Vault when working through Git Bash/WSL. Resolved by using `--vault-password-file`. +- **Cloud Permissions:** Initially, there were insufficient quotas and access rights in Yandex Cloud (Security Groups). Resolved by adding the `vpc.admin` role to the service account. \ No newline at end of file diff --git a/ansible/docs/screenshots/connection_check.png b/ansible/docs/screenshots/connection_check.png new file mode 100644 index 0000000000..0090d00332 Binary files /dev/null and b/ansible/docs/screenshots/connection_check.png differ diff --git a/ansible/docs/screenshots/deploy_check.png b/ansible/docs/screenshots/deploy_check.png new file mode 100644 index 0000000000..e5a98998be Binary files /dev/null and b/ansible/docs/screenshots/deploy_check.png differ diff --git a/ansible/docs/screenshots/docker_check.png b/ansible/docs/screenshots/docker_check.png new file mode 100644 index 0000000000..468ca070e1 Binary files /dev/null and b/ansible/docs/screenshots/docker_check.png differ diff --git a/ansible/docs/screenshots/idempotency.png b/ansible/docs/screenshots/idempotency.png new file mode 100644 index 0000000000..86c76ebb6a Binary files /dev/null and b/ansible/docs/screenshots/idempotency.png differ diff --git a/ansible/docs/screenshots/playbook_deploy.png b/ansible/docs/screenshots/playbook_deploy.png new file mode 100644 index 0000000000..742385e496 Binary files /dev/null and b/ansible/docs/screenshots/playbook_deploy.png differ diff --git a/ansible/docs/screenshots/provision_launch.png b/ansible/docs/screenshots/provision_launch.png new file mode 100644 index 0000000000..767d65e928 Binary files /dev/null and b/ansible/docs/screenshots/provision_launch.png differ diff --git a/ansible/inventory/group_vars/all.yml b/ansible/inventory/group_vars/all.yml new file mode 100644 index 0000000000..03cb181a00 --- /dev/null +++ b/ansible/inventory/group_vars/all.yml @@ -0,0 +1,18 @@ +$ANSIBLE_VAULT;1.1;AES256 +34313437303138653636386266316465306361646164613634383530313037333536316638376238 +3565316332613333316462396564343332633664363465370a343737643862393562623933353234 +65636462386462386462643536306233386465336465656262393733386662313335643230303631 +3166366162616366630a306665376138656534306437303236633866626432336461363931663762 +38663834663762323134633736663135303165376537613236353630653263363532646136363734 +37323536656262323531666564613838326530383832393163323839353435356262353531353837 +64313437353763346363323639646538653736373165333638666461323563643334633533303138 +66353564393664336461343633336336666331353761313831633532663964626134666332316565 +34616237373262366663663132633961323331353633386561376562356564396332373434653831 +64613530353934613839353366323164313266323439666439336334333663323030303133363063 +66636663303536613838663666353564343762333934343438353063326366366430666335353066 +33386437653830636233623936303638633838313164313737326337643764333833343764623462 +31336235666339383838623935336635636131383038643535653937363336386435623236323061 +34353435363363356263663730326138333837363432333837663366386561393465313861613934 +61633666643032623261356562356439353138636431303562383832323538663863333766363535 +30656133343966653461656264333165353532636639303337313031666133623731643436623236 +61303730326130326230616230373532613866383631393033616634323431376661 diff --git a/ansible/inventory/hosts.ini b/ansible/inventory/hosts.ini new file mode 100644 index 0000000000..925b318a12 --- /dev/null +++ b/ansible/inventory/hosts.ini @@ -0,0 +1,2 @@ +[web] +89.169.148.180 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa_linux diff --git a/ansible/playbooks/deploy.yml b/ansible/playbooks/deploy.yml new file mode 100644 index 0000000000..d626b9ce4e --- /dev/null +++ b/ansible/playbooks/deploy.yml @@ -0,0 +1,6 @@ +- name: deploy application + hosts: web + become: yes + + roles: + - app_deploy \ No newline at end of file diff --git a/ansible/playbooks/provision.yml b/ansible/playbooks/provision.yml new file mode 100644 index 0000000000..acd08d5f0b --- /dev/null +++ b/ansible/playbooks/provision.yml @@ -0,0 +1,7 @@ +- name: provision web servers + hosts: web + become: yes + + roles: + - common + - docker \ No newline at end of file diff --git a/ansible/roles/app_deploy/defaults/main.yml b/ansible/roles/app_deploy/defaults/main.yml new file mode 100644 index 0000000000..13840c8a70 --- /dev/null +++ b/ansible/roles/app_deploy/defaults/main.yml @@ -0,0 +1 @@ +restart_policy: unless-stopped \ No newline at end of file diff --git a/ansible/roles/app_deploy/handlers/main.yml b/ansible/roles/app_deploy/handlers/main.yml new file mode 100644 index 0000000000..158d17e4f9 --- /dev/null +++ b/ansible/roles/app_deploy/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart container + docker_container: + name: "{{ app_container_name }}" + state: restarted \ No newline at end of file diff --git a/ansible/roles/app_deploy/tasks/main.yml b/ansible/roles/app_deploy/tasks/main.yml new file mode 100644 index 0000000000..32e8a60e92 --- /dev/null +++ b/ansible/roles/app_deploy/tasks/main.yml @@ -0,0 +1,25 @@ +- name: login to docker hub + community.docker.docker_login: + username: "{{ dockerhub_username }}" + password: "{{ dockerhub_password }}" + no_log: false + +- name: pull docker image + community.docker.docker_image: + name: "{{ docker_image }}" + tag: "{{ docker_image_tag }}" + source: pull + +- name: stop old container + community.docker.docker_container: + name: "{{ app_container_name }}" + state: absent + +- name: run container + community.docker.docker_container: + name: "{{ app_container_name }}" + image: "{{ docker_image }}:{{ docker_image_tag }}" + state: started + restart_policy: "{{ restart_policy }}" + ports: + - "{{ app_port }}:{{ app_port }}" \ No newline at end of file diff --git a/ansible/roles/common/defaults/main.yml b/ansible/roles/common/defaults/main.yml new file mode 100644 index 0000000000..fb01629168 --- /dev/null +++ b/ansible/roles/common/defaults/main.yml @@ -0,0 +1,6 @@ +common_packages: + - python3-pip + - curl + - git + - vim + - htop \ No newline at end of file diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml new file mode 100644 index 0000000000..44c91ee80a --- /dev/null +++ b/ansible/roles/common/tasks/main.yml @@ -0,0 +1,9 @@ +- name: update apt cache + apt: + update_cache: yes + cache_valid_time: 3600 + +- name: install common packages + apt: + name: "{{ common_packages }}" + state: present \ No newline at end of file diff --git a/ansible/roles/docker/defaults/main.yml b/ansible/roles/docker/defaults/main.yml new file mode 100644 index 0000000000..254c295034 --- /dev/null +++ b/ansible/roles/docker/defaults/main.yml @@ -0,0 +1 @@ +docker_user: ubuntu \ No newline at end of file diff --git a/ansible/roles/docker/handlers/main.yml b/ansible/roles/docker/handlers/main.yml new file mode 100644 index 0000000000..f5700a7c2d --- /dev/null +++ b/ansible/roles/docker/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart docker + service: + name: docker + state: restarted \ No newline at end of file diff --git a/ansible/roles/docker/tasks/main.yml b/ansible/roles/docker/tasks/main.yml new file mode 100644 index 0000000000..447c2bfd4a --- /dev/null +++ b/ansible/roles/docker/tasks/main.yml @@ -0,0 +1,35 @@ +- name: add docker gpg key + apt_key: + url: https://download.docker.com/linux/ubuntu/gpg + state: present + +- name: add docker repo + apt_repository: + repo: "deb https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" + state: present + +- name: install docker packages + apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + state: present + update_cache: yes + +- name: ensure docker running + service: + name: docker + state: started + enabled: yes + +- name: add user to docker group + user: + name: "{{ docker_user }}" + groups: docker + append: yes + +- name: install python docker module + apt: + name: python3-docker + state: present \ No newline at end of file