Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
env
__pycache__
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use the official Python slim buster image as a base
FROM python:3.9-slim-buster

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file into the container
COPY ./analytics/requirements.txt requirements.txt

# Install system dependencies
RUN apt-get update && \
apt-get install -y build-essential libpq-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Upgrade pip and install Python dependencies
RUN pip install --upgrade pip setuptools wheel && \
pip install --no-cache-dir -r requirements.txt

# Copy the rest of the application code into the container
COPY ./analytics .

# Expose the port the app runs on
EXPOSE 5153

# Command to run the application
CMD ["python", "app.py"]
142 changes: 26 additions & 116 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,131 +1,41 @@
# Coworking Space Service Extension
The Coworking Space Service is a set of APIs that enables users to request one-time tokens and administrators to authorize access to a coworking space. This service follows a microservice pattern and the APIs are split into distinct services that can be deployed and managed independently of one another.
# Coworking Space Service Extension: Analytics API Deployment

For this project, you are a DevOps engineer who will be collaborating with a team that is building an API for business analysts. The API provides business analysts basic analytics data on user activity in the service. The application they provide you functions as expected locally and you are expected to help build a pipeline to deploy it in Kubernetes.
## Overview
The Coworking Space Service Analytics API provides business analysts with basic analytics data on user activity within the coworking space. The application is deployed within a Kubernetes environment managed via AWS EKS.

## Getting Started
## Technologies and Tools

### Dependencies
#### Local Environment
1. Python Environment - run Python 3.6+ applications and install Python dependencies via `pip`
2. Docker CLI - build and run Docker images locally
3. `kubectl` - run commands against a Kubernetes cluster
4. `helm` - apply Helm Charts to a Kubernetes cluster
- **Python 3.9+**: Core language for the analytics application.
- **Docker CLI**: To build, test, and run Docker images locally.
- **kubectl**: For managing Kubernetes clusters.
- **Helm**: For deploying and managing applications in Kubernetes.
- **AWS ECR**: Container Registry for storing Docker images.
- **AWS CodeBuild**: Automates image builds and pushes to ECR.
- **Kubernetes with AWS EKS**: The eks cluster should have the necessary permissions and policy for dynamic volumes creation
- **CloudWatch**: Monitoring and logging service to track application performance and health.

#### Remote Resources
1. AWS CodeBuild - build Docker images remotely
2. AWS ECR - host Docker images
3. Kubernetes Environment with AWS EKS - run applications in k8s
4. AWS CloudWatch - monitor activity and logs in EKS
5. GitHub - pull and clone code
## Deployment Process

### Setup
#### 1. Configure a Database
Set up a Postgres database using a Helm Chart.
**1. Database Setup:** We use the Bitnami Helm chart to deploy PostgreSQL in the Kubernetes cluster.
NB: After adding the Helm repository, modify the values.yaml file to add the database configuration, the storageclass for your eks cluster and the persistent volume configuration. Retrieve the password that will be used to connect to the database to run seed files.

1. Set up Bitnami Repo
```bash
helm repo add <REPO_NAME> https://charts.bitnami.com/bitnami
```
**2. Docker image Build:** Create the Dockerfile with the instructions to build the image. After building the image, push it to ECR

2. Install PostgreSQL Helm Chart
```
helm install <SERVICE_NAME> <REPO_NAME>/postgresql
```
**3. CodeBuild pipeline:** Create the CodeBuild project and define the buildspec.yml file with the necessary steps to automate the build process. Configure the project to trigger the pipeline with a push event in the GitHub repository.

This should set up a Postgre deployment at `<SERVICE_NAME>-postgresql.default.svc.cluster.local` in your Kubernetes cluster. You can verify it by running `kubectl svc`
**4. Kubernetes deployment:** Define the manifests to be used to deploy the app (in the deployment folder). Deploy the configmap, the secret, the deployment and the service to the cluster. Make sure the deployment configuration file uses the latest version of the docker image stored in ECR. Verify that the deployment is successful and test the application endpoints.

By default, it will create a username `postgres`. The password can be retrieved with the following command:
```bash
export POSTGRES_PASSWORD=$(kubectl get secret --namespace default <SERVICE_NAME>-postgresql -o jsonpath="{.data.postgres-password}" | base64 -d)
**5. Monitoring:** Install the amazon-cloudwatch-observability addon to be abble to monitor the application logs in CloudWatch

echo $POSTGRES_PASSWORD
```
## Releasing New Builds
To release new builds, follow these steps:

<sup><sub>* The instructions are adapted from [Bitnami's PostgreSQL Helm Chart](https://artifacthub.io/packages/helm/bitnami/postgresql).</sub></sup>
1. **Make Changes**: Implement the necessary changes or features in the codebase.

3. Test Database Connection
The database is accessible within the cluster. This means that when you will have some issues connecting to it via your local environment. You can either connect to a pod that has access to the cluster _or_ connect remotely via [`Port Forwarding`](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)
2. **Commit and Push**: Commit your changes and push them to the main branch. This action will trigger the CodeBuild pipeline.

* Connecting Via Port Forwarding
```bash
kubectl port-forward --namespace default svc/<SERVICE_NAME>-postgresql 5432:5432 &
PGPASSWORD="$POSTGRES_PASSWORD" psql --host 127.0.0.1 -U postgres -d postgres -p 5432
```
3. **Monitor Build Status**: Check the AWS CodeBuild console to monitor the build process. Ensure that the build completes successfully without errors.

* Connecting Via a Pod
```bash
kubectl exec -it <POD_NAME> bash
PGPASSWORD="<PASSWORD HERE>" psql postgres://postgres@<SERVICE_NAME>:5432/postgres -c <COMMAND_HERE>
```
4. **Modify the deployment manifest**: Use the latest image URI to deploy the app in kubernetes

4. Run Seed Files
We will need to run the seed files in `db/` in order to create the tables and populate them with data.

```bash
kubectl port-forward --namespace default svc/<SERVICE_NAME>-postgresql 5432:5432 &
PGPASSWORD="$POSTGRES_PASSWORD" psql --host 127.0.0.1 -U postgres -d postgres -p 5432 < <FILE_NAME.sql>
```

### 2. Running the Analytics Application Locally
In the `analytics/` directory:

1. Install dependencies
```bash
pip install -r requirements.txt
```
2. Run the application (see below regarding environment variables)
```bash
<ENV_VARS> python app.py
```

There are multiple ways to set environment variables in a command. They can be set per session by running `export KEY=VAL` in the command line or they can be prepended into your command.

* `DB_USERNAME`
* `DB_PASSWORD`
* `DB_HOST` (defaults to `127.0.0.1`)
* `DB_PORT` (defaults to `5432`)
* `DB_NAME` (defaults to `postgres`)

If we set the environment variables by prepending them, it would look like the following:
```bash
DB_USERNAME=username_here DB_PASSWORD=password_here python app.py
```
The benefit here is that it's explicitly set. However, note that the `DB_PASSWORD` value is now recorded in the session's history in plaintext. There are several ways to work around this including setting environment variables in a file and sourcing them in a terminal session.

3. Verifying The Application
* Generate report for check-ins grouped by dates
`curl <BASE_URL>/api/reports/daily_usage`

* Generate report for check-ins grouped by users
`curl <BASE_URL>/api/reports/user_visits`

## Project Instructions
1. Set up a Postgres database with a Helm Chart
2. Create a `Dockerfile` for the Python application. Use a base image that is Python-based.
3. Write a simple build pipeline with AWS CodeBuild to build and push a Docker image into AWS ECR
4. Create a service and deployment using Kubernetes configuration files to deploy the application
5. Check AWS CloudWatch for application logs

### Deliverables
1. `Dockerfile`
2. Screenshot of AWS CodeBuild pipeline
3. Screenshot of AWS ECR repository for the application's repository
4. Screenshot of `kubectl get svc`
5. Screenshot of `kubectl get pods`
6. Screenshot of `kubectl describe svc <DATABASE_SERVICE_NAME>`
7. Screenshot of `kubectl describe deployment <SERVICE_NAME>`
8. All Kubernetes config files used for deployment (ie YAML files)
9. Screenshot of AWS CloudWatch logs for the application
10. `README.md` file in your solution that serves as documentation for your user to detail how your deployment process works and how the user can deploy changes. The details should not simply rehash what you have done on a step by step basis. Instead, it should help an experienced software developer understand the technologies and tools in the build and deploy process as well as provide them insight into how they would release new builds.


### Stand Out Suggestions
Please provide up to 3 sentences for each suggestion. Additional content in your submission from the standout suggestions do _not_ impact the length of your total submission.
1. Specify reasonable Memory and CPU allocation in the Kubernetes deployment configuration
2. In your README, specify what AWS instance type would be best used for the application? Why?
3. In your README, provide your thoughts on how we can save on costs?

### Best Practices
* Dockerfile uses an appropriate base image for the application being deployed. Complex commands in the Dockerfile include a comment describing what it is doing.
* The Docker images use semantic versioning with three numbers separated by dots, e.g. `1.2.1` and versioning is visible in the screenshot. See [Semantic Versioning](https://semver.org/) for more details.
5. **Verify Deployment**: After the deployment is complete, verify that the new version is running correctly by checking the application logs in CloudWatch.
20 changes: 20 additions & 0 deletions buildspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: 0.2

phases:
pre_build:
commands:
- echo Logging into Docker Hub
- echo $DOCKER_HUB_PASSWORD | docker login --username $DOCKER_HUB_USERNAME --password-stdin
- echo Logging into ECR
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
build:
commands:
- echo Starting build at `date`
- echo Building the Docker image...
- docker build -t $IMAGE_REPO_NAME:$CODEBUILD_BUILD_NUMBER .
- docker tag $IMAGE_REPO_NAME:$CODEBUILD_BUILD_NUMBER $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_BUILD_NUMBER
post_build:
commands:
- echo Completed build at `date`
- echo Pushing the Docker image...
- docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_BUILD_NUMBER
18 changes: 5 additions & 13 deletions deployment/configmap.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: <NAME OF THE ConfigMap>
name: my-postgres-postgresql
data:
DB_NAME: <ENTER YOUR DB NAME HERE>
DB_USER: <ENTER YOUR USER NAME HERE>
DB_HOST: <ENTER YOUR DB HOST HERE>
DB_PORT: <ENTER YOUR DB PORT HERE>
---
apiVersion: v1
kind: Secret
metadata:
name: <NAME OF THE Secret>
type: Opaque
data:
<THE KEY FROM Secret WHICH has THE ENCODED PASSWORD>: <OUTPUT OF `echo -n 'the password' | base64`>
DB_NAME: "mydatabase"
DB_USERNAME: "myuser"
DB_HOST: "my-postgres-postgresql.default.svc.cluster.local"
DB_PORT: "5432"
10 changes: 5 additions & 5 deletions deployment/coworking.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ spec:
spec:
containers:
- name: coworking
image: <DOCKER_IMAGE_URI_FROM_ECR>
image: 597052192244.dkr.ecr.us-east-1.amazonaws.com/coworking-app:latest
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
Expand All @@ -46,11 +46,11 @@ spec:
timeoutSeconds: 5
envFrom:
- configMapRef:
name: <NAME OF THE ConfigMap>
name: my-postgres-postgresql
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: <NAME OF THE Secret>
key: <THE KEY FROM Secret WHICH has THE ENCODED PASSWORD>
restartPolicy: Always
name: my-postgres-postgresql
key: DB_PASSWORD
restartPolicy: Always
7 changes: 7 additions & 0 deletions deployment/secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: my-postgres-postgresql
type: Opaque
data:
DB_PASSWORD: bXlwYXNzd29yZA==
Binary file added screenshots/2-1 codebuild project.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/2-2 codebuild trigger.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/2-3-codebuild pipeline.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/3- ECR repository.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/4- get services.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/5- kubectl get pods.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/6- kubectl describe svc database.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/7-1-kubectl describe deployment.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/8-1-cloudwatch log-groups.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/8-2-cloudwatch application logs.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.