Skip to content
Open

Lab5 #1072

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
10d3eec
created the project foler
haraphat01 Jun 5, 2023
ea7d0ac
Submitting the first lab for review
haraphat01 Jun 5, 2023
730c9a4
updated the readme with the docker instruction and also added docker …
haraphat01 Jun 5, 2023
274912b
Added Github action to the project
haraphat01 Jun 5, 2023
33ce6ee
Added Github action to the project
haraphat01 Jun 5, 2023
799ebdb
Added Github action to the project
haraphat01 Jun 5, 2023
6ae43df
added the github workflows
haraphat01 Jun 5, 2023
8c60aef
Fixing the bug on the github action
haraphat01 Jun 5, 2023
9a03421
Fixing the bug on the github action
haraphat01 Jun 5, 2023
7705a25
Fixing the bug on the github action
haraphat01 Jun 6, 2023
6808a07
Fixing the bug on the github action
haraphat01 Jun 6, 2023
54626b3
Fixing the bug on the github action
haraphat01 Jun 6, 2023
4e829ba
Fixing the bug on the github action
haraphat01 Jun 6, 2023
848afa1
Fixing the bug on the github action
haraphat01 Jun 6, 2023
6794b88
Fixing the bug on the github action
haraphat01 Jun 6, 2023
34181a4
Fixing the bug on the github action
haraphat01 Jun 6, 2023
93f19e4
Fixing the bug on the github action
haraphat01 Jun 6, 2023
e7df1e9
Fixing the bug on the github action configuration
haraphat01 Jun 6, 2023
e81501b
Updated the CI action
haraphat01 Jun 6, 2023
3f7c037
Fixing the bug on the github action configuration
haraphat01 Jun 6, 2023
053db9d
Fixing the bug on the github action configuration
haraphat01 Jun 6, 2023
7386686
Added a comment to the main file
haraphat01 Jun 6, 2023
c6875ba
Added a comment to the main file
haraphat01 Jun 6, 2023
3d21bdf
Added a comment to the main file
haraphat01 Jun 6, 2023
a9bd2c6
Fixing the bug on the github action configuration
haraphat01 Jun 6, 2023
6fe7211
Fixing the bug on the github action configuration
haraphat01 Jun 7, 2023
0a609e4
Added a comment to the main file
haraphat01 Jun 7, 2023
2e00bc8
Reworked on the github action
haraphat01 Jun 7, 2023
1ece351
Reworked on the github action
haraphat01 Jun 7, 2023
a93ef12
Reworked on the github action
haraphat01 Jun 7, 2023
baa03fb
Added the terraform file
haraphat01 Jun 10, 2023
09ea6c1
Trying to solve the big file size issue
haraphat01 Jun 11, 2023
31a1591
Added the TF.md file and the output
haraphat01 Jun 11, 2023
7a47bd9
Added ansible yml and a docker role
haraphat01 Jun 12, 2023
5371f20
Working on the ansible file
haraphat01 Jun 14, 2023
9fb92bf
updated the ansible file
haraphat01 Jun 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Python CI

on:
push:
branches: [lab3]
paths:
- "app_python/**"
- ".github/workflows/main.yaml"

jobs:
build_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.10.7'
- name: Install dependencies
run: pip install -r app_python/requirements.txt
- name: Upgrade Flask and Werkzeug
run: pip install --upgrade Flask
- name: Run unit tests
run: python3 app_python/test_main.py

deploy:
needs: build_test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Log in to Docker registry
uses: docker/login-action@v1
with:
registry: docker.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
file: app_python/Dockerfile
push: true
tags: docker.io/haraphat01/moscowtime:tagname

110 changes: 68 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,92 @@
# Labs
# Current Time in Moscow

## Introduction
![Python CI](https://github.com/haraphat01/moscow_time/workflows/Python%20CI/badge.svg)

Welcome to DevOps course labs. All labs are practical and will be built on each other. You will implement simple application, containerize it, implement simple tests, prepare an infrastructure and CI/CD processes, collect metrics, logs, etc.

## Architecture
## Overview
This is a simple Python web application that displays the current time in Moscow. It uses the Flask web framework and the datetime module to get the current time in the Europe/Moscow timezone. The time is displayed in a user-friendly format on a web page.

This repository contains a master branch with introduction and one branch with instructions for each lab.
## Build
To build this application, you need to create a Python file with a main.py extension, for example, app.py. Then, copy the code in main.py to your file. Save the file and run it using the command python app.py in a terminal or command prompt.
The application will start running on your local machine.

## Rules
## Usage
To use the application, open a web browser and navigate to http://localhost:5000/. The current time in Moscow will be displayed on the web page. The time will be updated every time you refresh the page.

Each labs requires the participant to finish all previous labs, therefore **participants are required to submit each lab and get at least 6/10 points for each lab to pass the course**.
## To run the Dockerfile in your project, you can follow these steps:

Grading is based on PRs with your solution to the corresponding branch of this repository. This repository is read-only for all participants, therefore to be able to create a pull request, a participant should fork this repository to his own workspace and solve the lab there. It is recommended to build a solution of a lab N upon a solution of lab N-1, so choose workflow in your fork of this repository wisely. Structure of your repository will not affect your grade, only state of your repository from which the PR is created will be checked and graded (state after last commit in your PR on corresponding lab).
1. Make sure that you have Docker installed on your local machine. You can download Docker from the official website: https://www.docker.com/products/docker-desktop

### Recommended workflow
2. Open a terminal or command prompt and navigate to the directory that contains your Dockerfile.

#### For the first lab
3. Build the Docker image using the following command:
docker build -t <image-name> .
Make sure to replace <image-name> with the name that you want to give to your Docker image. The . at the end of the command specifies that the build context is the current directory.

1. Fork this repository.
2. Checkout to lab1 branch.
3. Complete lab1 tasks.
4. Push the code to your repository.
5. Create a PR to the lab1 branch on this repository from your fork's lab1 branch.
6. Create an archive with the current version of your code and submit a zip file to Moodle.
7. Create a team with with your classmates, 6 people max.
8. Each student must review PRs of all teammates.
9. Wait for your grade.
4. Once the build is complete, you can run the Docker container using the following command:
docker run -p <host-port>:<container-port> <image-name>

## Grading
Make sure to replace <host-port> with the port number on your local machine that you want to use to access the container, <container-port> with the port number that your application is listening on inside the container, and <image-name> with the name of the Docker image that you built in step 3.

### Points distribution for the course
For example, if your application is listening on port 80 inside the container and you want to access it on port 8080 on your local machine, you can use the following command:
docker run -p 8080:80 <image-name>

```
70 - labs
20 - final exam
10 - attendance on lectures
```
5. Once the container is running, you can access your application by opening a web browser and navigating to http://localhost:<host-port>. In the example above, you would navigate to http://localhost:8080.

### Grade ranges
## Unit tests

```
[90;100] - A
[75;90) - B
[60;75) - C
[0;60) - D
```
I have written unit tests for the Python web application that displays the current time in Moscow. These tests ensure that the application is working as expected and help us catch any bugs early in the development process.

### Labs grading
To run the unit tests, navigate to the directory where the `test_main.py` file is located and run the following command:
python test_main.py

Each lab is marked out of 10. All labs have a set of main tasks and a set of extra tasks.

Completing main tasks correctly will give you 10 points out of 10. Completing extra tasks correctly will give you some additional points, depends on the bonus task difficulty. Your points for main and extra tasks will be summed up and will help you to get a better grade.
Make sure that you have all the necessary dependencies installed, including Flask and any other modules that your application depends on.

If you finish all bonus tasks correctly the **permission to skip the exam will be granted to you + 10 extra points**. If you finish not all of them you will must pass the exam, but it can save you from the exam's failure.
If the tests pass successfully, you should see output similar to the following:

## Deadlines and labs distribution
Ran 1 test in 0.001s

Participants have 2 new labs every week simultaneously and 1 week to submit solutions. Moodle will contain presentations and deadlines.
OK

You are required to submit a zip file with your source code to corresponding assignment in moodle. This is required for the university as a proof of work.

## Submission policy
## Git Actions CI

**Submitting results after the deadline will result in maximum of 6 points for the corresponding lab. As stated before, all labs must be submitted to pass the course.**
I have set up a continuous integration (CI) workflow using Git Actions to build and test our Python web application. The workflow has three steps: installing dependencies, running linters, and running unit tests.

To run the workflow, push changes to the `main` branch of the repository. The workflow will automatically be triggered and the steps will be run in order. Make sure that you have all the necessary dependencies installed, including Flask and any other modules that your application depends on.

I have also added Docker-related steps to our workflow to log in to a Docker registry, build a Docker image, and push the image to the registry. To use these steps, you will need to set up the `DOCKER_USERNAME` and `DOCKER_PASSWORD` secrets in your repository settings.

By following these best practices and including a Git Actions CI workflow in your project, I can ensure that my application is thoroughly tested and working as expected.

# Terraform AWS Example

This Terraform configuration sets up an AWS infrastructure with a single EC2 instance running in the `us-west-2` region. The instance is tagged with the name "ExampleAppServerInstance".

## Prerequisites

- Terraform >= 1.2.0
- AWS CLI
- An AWS account with the necessary permissions

## Configuration

The `main.tf` file contains the following resources:

1. **Terraform block**: Specifies the required providers and their versions.
2. **AWS provider block**: Configures the AWS provider with the `us-west-2` region.
3. **AWS instance resource**: Creates an EC2 instance with the specified AMI and instance type.


## Usage

1. Install Terraform and the AWS CLI.
2. Configure your AWS credentials using `aws configure` or by setting the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
3. Run `terraform init` to initialize the Terraform working directory.
4. Run `terraform apply` to create the infrastructure. Confirm the changes when prompted.
5. To destroy the infrastructure when you're done, run `terraform destroy`.

## Customization

You can customize the configuration by modifying the `main.tf` file. For example, you can change the instance type, region, or add additional resources as needed.
6 changes: 6 additions & 0 deletions ansible/ANSIBLE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
WARNING]: Unable to parse
/home/pencil/Desktop/Work/DevOps/labss/ansible/inventory/default_aws_ec2.yml as
an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'
6 changes: 6 additions & 0 deletions ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[defaults]
inventory = ./inventory/default_aws_ec2.yml
remote_user = ubuntu

[privilege_escalation]
become = True
3 changes: 3 additions & 0 deletions ansible/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
# defaults file for docker
docker_restart_handler: restart docker
6 changes: 6 additions & 0 deletions ansible/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
- name: restart docker
systemd:
name: docker
state: restarted
become: true
4 changes: 4 additions & 0 deletions ansible/playbook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
- hosts: all
roles:
- docker
13 changes: 13 additions & 0 deletions ansible/roles/docker/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
- name: Install Docker
apt:
name: docker.io
state: present
become: true

- name: Ensure Docker service is started
systemd:
name: docker
state: started
enabled: true
become: true
15 changes: 15 additions & 0 deletions app_python/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3-alpine
USER root
WORKDIR /main

COPY app_python/requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8081

CMD ["python3", "main.py"]


17 changes: 17 additions & 0 deletions app_python/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from datetime import datetime

from flask import Flask

app = Flask(__name__)

def get_current_time():
now = datetime.now()
current_time = now.strftime("Current Time in Moscow: %Y-%m-%d %H:%M:%S")
return current_time

@app.route('/')
def home():
return get_current_time()

if __name__ == '__main__':
app.run(host="0.0.0.0", debug=True)
2 changes: 2 additions & 0 deletions app_python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pytz
Flask==2.0.1
14 changes: 14 additions & 0 deletions app_python/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import unittest
from main import app

class TestApp(unittest.TestCase):
def setUp(self):
self.app = app.test_client()

def test_homepage(self):
response = self.app.get('/')
self.assertEqual(response.status_code, 200)
self.assertIn(b'Current Time in Moscow', response.data)

if __name__ == '__main__':
unittest.main()
73 changes: 73 additions & 0 deletions terraform/TF.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Output of Terraform show
docker_container.nginx:
resource “docker_container” “nginx” { attach = false command = [ “nginx”, “-g”, “daemon off;”, ] container_read_refresh_timeout_milliseconds =
15000 cpu_shares = 0 entrypoint = [ “/docker-entrypoint.sh”, ] env = [] hostname = “21dca2656095” id =
“21dca2656095460e1391309cc5904b687acdaee6500a047df9493911addb239c” image =
“sha256:f9c14fe76d502861ba0939bc3189e642c02e257f06f4c0214b1f8ca329326cda” init = false ipc_mode = “private” log_driver = “json-file” logs =
false max_retry_count = 0 memory = 0 memory_swap = 0 must_run = true name = “tutorial” network_data = [ { gateway = “172.17.0.1”
global_ipv6_address = “” global_ipv6_prefix_length = 0 ip_address = “172.17.0.2” ip_prefix_length = 16 ipv6_gateway = “” mac_address = “02:42:ac
11:00:02” network_name = “bridge” }, ] network_mode = “default” privileged = false publish_all_ports = false read_only = false remove_volumes =
true restart = “no” rm = false runtime = “runc” security_opts = [] shm_size = 64 start = true stdin_open = false stop_signal = “SIGQUIT” stop_timeout
= 0 tty = false wait = false wait_timeout = 60
ports {
external = 8000
internal = 80
ip = "0.0.0.0"
protocol = "tcp"
}

}
docker_image.nginx:
resource “docker_image” “nginx” { id = “sha256:f9c14fe76d502861ba0939bc3189e642c02e257f06f4c0214b1f8ca329326cdanginx:latest” image_id =
“sha256:f9c14fe76d502861ba0939bc3189e642c02e257f06f4c0214b1f8ca329326cda” keep_locally = false name = “nginx:latest” repo_digest =
“nginx@sha256:af296b188c7b7df99ba960ca614439c99cb7cf252ed7bbc23e90cfda59092305” }

# Output of terraform state list
docker_container.nginx docker_image.nginx
aws_instance.app_server:
resource “aws_instance” “app_server” { ami = “ami-08d70e59c07c61a3a” arn = “arn:aws:ec2:us-west-2:354156216263:instance
i-0b39be7dc8d0a893a” associate_public_ip_address = true availability_zone = “us-west-2a” cpu_core_count = 1 cpu_threads_per_core = 1
disable_api_stop = false disable_api_termination = false ebs_optimized = false get_password_data = false hibernation = false id =
“i-0b39be7dc8d0a893a” instance_initiated_shutdown_behavior = “stop” instance_state = “running” instance_type = “t2.micro” ipv6_address_count =
0 ipv6_addresses = [] monitoring = false placement_partition_number = 0 primary_network_interface_id = “eni-0cc62b162b9c9df4c” private_dns =
“ip-172-31-16-27.us-west-2.compute.internal” private_ip = “172.31.16.27” public_dns = “ec2-35-93-162-232.us-west-2.compute.amazonaws.com”
public_ip = “35.93.162.232” secondary_private_ips = [] security_groups = [ “default”, ] source_dest_check = true subnet_id =
“subnet-039b0778d5eaf2eb4” tags = { “Name” = “ExampleAppServerInstance” } tags_all = { “Name” = “ExampleAppServerInstance” } tenancy =
“default” user_data_replace_on_change = false vpc_security_group_ids = [ “sg-0849ce7988dae5104”, ]
capacity_reservation_specification {
capacity_reservation_preference = "open"
}
cpu_options {
core_count = 1
threads_per_core = 1
}
credit_specification {
cpu_credits = "standard"
}
enclave_options {
enabled = false
}
maintenance_options {
auto_recovery = "default"
}metadata_options {
http_endpoint = "enabled"
http_put_response_hop_limit = 1
http_tokens = "optional"
instance_metadata_tags = "disabled"
}
private_dns_name_options {
enable_resource_name_dns_a_record = false
enable_resource_name_dns_aaaa_record = false
hostname_type = "ip-name"
}
root_block_device {
delete_on_termination = true
device_name = "/dev/sda1"
encrypted = false
iops = 100
tags = {}
throughput = 0
volume_id = "vol-0403cb7cdf11b3fb7"
volume_size = 8
volume_type = "gp2"
}
24 changes: 24 additions & 0 deletions terraform/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0.1"
}
}
}

provider "docker" {}

resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = false
}

resource "docker_container" "nginx" {
image = docker_image.nginx.image_id
name = "tutorial"
ports {
internal = 80
external = 8000
}
}