diff --git a/DOCKER_BUILD_STEPS.md b/DOCKER_BUILD_STEPS.md new file mode 100644 index 00000000..85555d7f --- /dev/null +++ b/DOCKER_BUILD_STEPS.md @@ -0,0 +1,207 @@ +# Docker Build Steps - Local Testing + +## Prerequisites +✅ Docker installed (version 28.4.0 detected) +✅ ECR repository created (Screenshot 12 captured) +⏳ Docker Desktop needs to be running + +--- + +## Step 1: Start Docker Desktop + +1. Open **Docker Desktop** application on Windows +2. Wait for Docker to start (you'll see "Docker Desktop is running" in the system tray) +3. Verify Docker is running: + ```powershell + docker ps + ``` + Should return a list (even if empty) without errors + +--- + +## Step 2: Build Docker Image Locally + +### Navigate to analytics directory: +```powershell +cd C:\Users\Domzi\Desktop\Projects\cd12355-microservices-aws-kubernetes-project-starter\analytics +``` + +### Build the image: +```powershell +docker build -t test-coworking-analytics . +``` + +**Expected output:** +``` +[+] Building 45.2s (12/12) FINISHED + => [internal] load build definition from Dockerfile + => => transferring dockerfile: 456B + => [internal] load .dockerignore + => [internal] load metadata for docker.io/library/python:3.11-slim + => [1/6] FROM docker.io/library/python:3.11-slim + => [2/6] WORKDIR /app + => [3/6] RUN apt-get update -y && apt-get install -y build-essential libpq-dev + => [4/6] COPY requirements.txt . + => [5/6] RUN pip install --no-cache-dir --upgrade pip setuptools wheel + => [6/6] COPY . . + => exporting to image + => => exporting layers + => => writing image sha256:abc123... + => => naming to docker.io/library/test-coworking-analytics +``` + +📸 **Screenshot 10**: Capture the successful build output + +--- + +## Step 3: Verify the Docker Image + +### List Docker images: +```powershell +docker images +``` + +You should see: +``` +REPOSITORY TAG IMAGE ID CREATED SIZE +test-coworking-analytics latest abc123def456 2 minutes ago 200MB +``` + +--- + +## Step 4: Test Docker Image with Host Network + +### Important: Stop the local Flask app first! +- If you have the Flask app running in a command window, close it +- Or press Ctrl+C to stop it + +### Run the Docker container: +```powershell +docker run --network="host" test-coworking-analytics +``` + +**Expected output:** +``` + * Serving Flask app 'config' + * Debug mode: off +WARNING: This is a development server. Do not use it in a production deployment. + * Running on all addresses (0.0.0.0) + * Running on http://127.0.0.1:5153 + * Running on http://192.168.x.x:5153 +Press CTRL+C to quit +``` + +📸 **Screenshot 11**: Capture the Docker container running + +--- + +## Step 5: Test the Dockerized Application + +### Open a NEW PowerShell window and test: + +```powershell +# Health check +curl http://127.0.0.1:5153/health_check + +# Readiness check +curl http://127.0.0.1:5153/readiness_check + +# Daily usage report +curl http://127.0.0.1:5153/api/reports/daily_usage + +# User visits report +curl http://127.0.0.1:5153/api/reports/user_visits +``` + +**Expected results:** +- Health check: "ok" +- Readiness check: "ok" +- Daily usage: JSON with dates and visit counts +- User visits: JSON with user IDs and visit data + +--- + +## Step 6: Stop the Docker Container + +Press **Ctrl+C** in the window where Docker is running + +Or in another terminal: +```powershell +# List running containers +docker ps + +# Stop the container +docker stop +``` + +--- + +## Troubleshooting + +### Error: "Cannot connect to the Docker daemon" +**Solution**: Start Docker Desktop application + +### Error: "port is already allocated" +**Solution**: +- Stop the local Flask app (close the command window) +- Or stop any other container using port 5153: + ```powershell + docker ps + docker stop + ``` + +### Error: "database connection failed" +**Solution**: Make sure port forwarding is still active: +```powershell +kubectl port-forward service/postgresql-service 5433:5432 +``` +Run this in a separate terminal window + +### Error: Building takes too long +**Solution**: This is normal for the first build (downloading base image). Subsequent builds will be faster. + +--- + +## Next Steps After Local Testing + +Once you've verified the Docker image works locally: + +1. ✅ Docker image builds successfully +2. ✅ Docker container runs and connects to database +3. ✅ API endpoints respond correctly +4. ⏭️ **Next**: Set up CodeBuild to automate builds +5. ⏭️ Push image to ECR +6. ⏭️ Deploy to Kubernetes + +--- + +## Notes + +- The `--network="host"` flag allows the Docker container to access localhost:5433 (port-forwarded database) +- In production (Kubernetes), we won't use host network - the app will connect directly to the postgresql-service +- Local testing is optional but recommended to verify the Dockerfile works correctly + +--- + +## Summary Commands + +```powershell +# Build +cd analytics +docker build -t test-coworking-analytics . + +# Run (make sure Flask app is stopped first) +docker run --network="host" test-coworking-analytics + +# Test in another window +curl http://127.0.0.1:5153/health_check + +# Stop +# Press Ctrl+C or: +docker ps +docker stop +``` + +--- + +**Ready to proceed with CodeBuild setup!** 🚀 diff --git a/analytics/Dockerfile b/analytics/Dockerfile new file mode 100644 index 00000000..300569f5 --- /dev/null +++ b/analytics/Dockerfile @@ -0,0 +1,22 @@ + +# Use Python Python 3.10 as the base image +FROM public.ecr.aws/docker/library/python:3.10-alpine + +# Set the working directory inside the container +WORKDIR /app + +# Copy the current directory contents to the container at /app +COPY /analytics/ /app + +# Install dependencies from requirements.txt +RUN pip install --no-cache-dir -r /app/requirements.txt + +# Expose port 5000 +EXPOSE 5000 + +# Set an environment variable +ENV NAME World + +# Run the application when the container starts +CMD ["python", "app/app.py"] +CMD python app.py diff --git a/analytics/__pycache__/config.cpython-313.pyc b/analytics/__pycache__/config.cpython-313.pyc new file mode 100644 index 00000000..3b10f3bb Binary files /dev/null and b/analytics/__pycache__/config.cpython-313.pyc differ diff --git a/analytics/run_app.bat b/analytics/run_app.bat new file mode 100644 index 00000000..00b4e52f --- /dev/null +++ b/analytics/run_app.bat @@ -0,0 +1,11 @@ +@echo off +cd /d "%~dp0" +set DB_USERNAME=myuser +set DB_PASSWORD=mypassword +set DB_HOST=127.0.0.1 +set DB_PORT=5433 +set DB_NAME=mydatabase +echo Starting Flask application... +echo Database: %DB_NAME% at %DB_HOST%:%DB_PORT% +python app.py +pause diff --git a/analytics/run_app.ps1 b/analytics/run_app.ps1 new file mode 100644 index 00000000..507c70bd --- /dev/null +++ b/analytics/run_app.ps1 @@ -0,0 +1,8 @@ +$env:DB_USERNAME="myuser" +$env:DB_PASSWORD="mypassword" +$env:DB_HOST="127.0.0.1" +$env:DB_PORT="5433" +$env:DB_NAME="mydatabase" + +python app.py + diff --git a/buildspec.yaml b/buildspec.yaml new file mode 100644 index 00000000..b1076a67 --- /dev/null +++ b/buildspec.yaml @@ -0,0 +1,35 @@ +version: 0.2 + +phases: + pre_build: + commands: + - echo Logging in to Amazon 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 + - REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME + - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) + - IMAGE_TAG=${COMMIT_HASH:=latest} + + build: + commands: + - echo Build started on `date` + - echo Building the Docker image... + - cd analytics + - docker build -t $REPOSITORY_URI:latest . + - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG + - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$CODEBUILD_BUILD_NUMBER + + post_build: + commands: + - echo Build completed on `date` + - echo Pushing the Docker images... + - docker push $REPOSITORY_URI:latest + - docker push $REPOSITORY_URI:$IMAGE_TAG + - docker push $REPOSITORY_URI:$CODEBUILD_BUILD_NUMBER + - echo Writing image definitions file... + - printf '[{"name":"%s","imageUri":"%s"}]' $IMAGE_REPO_NAME $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json + +artifacts: + files: + - imagedefinitions.json + - '**/*' + diff --git a/deployment/configmap.yaml b/deployment/configmap.yaml index 7dcae113..7cb1f6d8 100644 --- a/deployment/configmap.yaml +++ b/deployment/configmap.yaml @@ -1,17 +1,9 @@ apiVersion: v1 kind: ConfigMap metadata: - name: + name: coworking-configmap data: - DB_NAME: - DB_USER: - DB_HOST: - DB_PORT: ---- -apiVersion: v1 -kind: Secret -metadata: - name: -type: Opaque -data: - : \ No newline at end of file + DB_HOST: "postgresql-service" + DB_PORT: "5432" + DB_NAME: "mydatabase" + DB_USERNAME: "myuser" \ No newline at end of file diff --git a/deployment/coworking.yaml b/deployment/coworking.yaml index cf86a612..2244d1a6 100644 --- a/deployment/coworking.yaml +++ b/deployment/coworking.yaml @@ -30,8 +30,8 @@ spec: spec: containers: - name: coworking - image: - imagePullPolicy: IfNotPresent + image: .dkr.ecr..amazonaws.com/coworking:latest + imagePullPolicy: Always livenessProbe: httpGet: path: /health_check @@ -40,17 +40,17 @@ spec: timeoutSeconds: 2 readinessProbe: httpGet: - path: "/readiness_check" + path: /readiness_check port: 5153 initialDelaySeconds: 5 timeoutSeconds: 5 envFrom: - configMapRef: - name: + name: coworking-configmap env: - name: DB_PASSWORD valueFrom: secretKeyRef: - name: - key: + name: coworking-secret + key: DB_PASSWORD restartPolicy: Always \ No newline at end of file diff --git a/deployment/secret.yaml b/deployment/secret.yaml new file mode 100644 index 00000000..3c9fbfd0 --- /dev/null +++ b/deployment/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: coworking-secret +type: Opaque +data: + DB_PASSWORD: bXlwYXNzd29yZA== + diff --git a/postgresql-deployment.yaml b/postgresql-deployment.yaml new file mode 100644 index 00000000..f97a3c1d --- /dev/null +++ b/postgresql-deployment.yaml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgresql +spec: + replicas: 1 + selector: + matchLabels: + app: postgresql + template: + metadata: + labels: + app: postgresql + spec: + containers: + - name: postgresql + image: postgres:15 + env: + - name: POSTGRES_DB + value: mydatabase + - name: POSTGRES_USER + value: myuser + - name: POSTGRES_PASSWORD + value: mypassword + ports: + - containerPort: 5432 diff --git a/postgresql-service.yaml b/postgresql-service.yaml new file mode 100644 index 00000000..e34ee0e3 --- /dev/null +++ b/postgresql-service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: postgresql-service +spec: + type: ClusterIP + ports: + - port: 5432 + targetPort: 5432 + selector: + app: postgresql + diff --git a/pv.yaml b/pv.yaml new file mode 100644 index 00000000..99bc5f0b --- /dev/null +++ b/pv.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: my-manual-pv +spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: gp2 + hostPath: + path: "/mnt/data" + diff --git a/pvc.yaml b/pvc.yaml new file mode 100644 index 00000000..097a7d8c --- /dev/null +++ b/pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postgresql-pvc +spec: + storageClassName: gp2 + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + diff --git a/test_api.ps1 b/test_api.ps1 new file mode 100644 index 00000000..13e260df --- /dev/null +++ b/test_api.ps1 @@ -0,0 +1,14 @@ +# Test the analytics API endpoints + +Write-Host "Testing health check..." -ForegroundColor Green +curl http://127.0.0.1:5153/health_check + +Write-Host "`n`nTesting readiness check..." -ForegroundColor Green +curl http://127.0.0.1:5153/readiness_check + +Write-Host "`n`nTesting daily usage report..." -ForegroundColor Green +curl http://127.0.0.1:5153/api/reports/daily_usage + +Write-Host "`n`nTesting user visits report..." -ForegroundColor Green +curl http://127.0.0.1:5153/api/reports/user_visits +