From 7ddcd49ec741cb0ae671709ec5a501522c603cf8 Mon Sep 17 00:00:00 2001 From: Soe Thura Date: Sat, 11 May 2024 00:25:24 +0630 Subject: [PATCH] Setup cicd --- .dockerignore | 3 ++ .github/workflows/main.yml | 70 ++++++++++++++++++++++++++++ Dockerfile | 29 ++++++++++++ devops/playbook.yml | 85 ++++++++++++++++++++++++++++++++++ devops/templates/nginx.conf.j2 | 27 +++++++++++ 5 files changed, 214 insertions(+) create mode 100644 .dockerignore create mode 100644 .github/workflows/main.yml create mode 100644 Dockerfile create mode 100644 devops/playbook.yml create mode 100644 devops/templates/nginx.conf.j2 diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..001154b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +/.github/workflows +/devops +/node_modules \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..1af4df4 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,70 @@ +name: Build and Push Docker Image + +env: + SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + + SSH_USER: ${{ vars.SSH_USER }} + TARGET_HOST: ${{ vars.SSH_HOST }} + IMAGE_NAME: ${{ vars.IMAGE_NAME }} + DOMAIN_NAME: ${{ vars.DOMAIN_NAME }} + +on: + push: + branches: + - develop + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Login to Docker Hub with token + run: | + echo $DOCKERHUB_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin + + - name: Build and push Docker image + run: | + docker build -t $IMAGE_NAME:latest . + docker push $IMAGE_NAME:latest + + + deploy: + needs: build + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Create SSH key + run: | + echo "$SSH_PRIVATE_KEY" > private.key + sudo chmod 400 private.key + eval `ssh-agent -s` + ssh-add private.key + mkdir -p ~/.ssh + touch ~/.ssh/known_hosts + chmod 644 ~/.ssh/known_hosts + ssh-keyscan -H $TARGET_HOST >> ~/.ssh/known_hosts + + - name: Set up Ansible + run: | + sudo apt-get update + sudo apt-get install -y ansible + + - name: Creae inventory file + run: | + echo "server ansible_host=$TARGET_HOST ansible_user=$SSH_USER ansible_ssh_private_key_file=private.key" > inventory + + - name: Deploy with Ansible + run: | + ansible-playbook -i inventory \ + --extra-vars "image_name=$IMAGE_NAME" \ + --extra-vars "domain_name=$DOMAIN_NAME" \ + --extra-vars "dockerhub_username=$DOCKERHUB_USERNAME" \ + --extra-vars "dockerhub_token=$DOCKERHUB_TOKEN" \ + --extra-vars "ansible_ssh_common_args='-o StrictHostKeyChecking=no'" \ + devops/playbook.yml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..251ced5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,29 @@ +FROM node:20-alpine + +LABEL maintainer="Soe Thura " +LABEL description="Docker image for Next.js app" + +# Set working directory +WORKDIR /app + +# Copy package.json and package-lock.json +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application code excluding the files in .dockerignore +COPY . . + +# Build the Next.js app +RUN npm run build + +# Expose port 3000 +EXPOSE 3000 + +# Command to run the Next.js app +CMD ["npm", "start"] + +# Build the Docker image +# docker build -t nextjs-app . +# docker run -p 3000:3000 -d --name nextjs-app nextjs-app diff --git a/devops/playbook.yml b/devops/playbook.yml new file mode 100644 index 0000000..5a07a51 --- /dev/null +++ b/devops/playbook.yml @@ -0,0 +1,85 @@ +--- +- name: Deploy Next.js Docker container + hosts: all + become: yes + vars: + IMAGE_NAME: "{{ image_name }}" + DOCKERHUB_USERNAME: "{{ dockerhub_username }}" + DOCKERHUB_TOKEN: "{{ dockerhub_token }}" + DOMAIN_NAME: "{{ domain_name }}" + + tasks: + - name: Run Apt update + apt: + update_cache: yes + + - name: Install Docker + apt: + name: docker.io + state: present + + - name: Start Docker service + service: + name: docker + state: started + + - name: Install Nginx + apt: + name: nginx + state: present + + - name: Start Nginx service + service: + name: nginx + state: started + + - name: Login to Docker Hub with token + docker_login: + username: "{{ DOCKERHUB_USERNAME }}" + password: "{{ DOCKERHUB_TOKEN }}" + + - name: Pull Docker image + docker_image: + name: "{{ IMAGE_NAME }}" + source: pull + + - name: Run Docker container + docker_container: + name: nextjs_container + image: "{{ IMAGE_NAME }}" + state: started + restart_policy: always + ports: + - "3001:3000" + + - name: Wait for container to start + wait_for: + host: localhost + port: 3001 + delay: 5 + timeout: 60 + + - name: Check if Nginx config file exists + stat: + path: "/etc/nginx/sites-available/{{ DOMAIN_NAME }}" + register: nginx_config + + - name: Configure Nginx + template: + src: nginx.conf.j2 + dest: "/etc/nginx/sites-available/{{ DOMAIN_NAME }}" + when: not nginx_config.stat.exists + + - name: Enable Nginx site + file: + src: "/etc/nginx/sites-available/{{ DOMAIN_NAME }}" + dest: "/etc/nginx/sites-enabled/{{ DOMAIN_NAME }}" + state: link + when: not nginx_config.stat.exists + notify: Reload Nginx + + handlers: + - name: Reload Nginx + service: + name: nginx + state: reloaded diff --git a/devops/templates/nginx.conf.j2 b/devops/templates/nginx.conf.j2 new file mode 100644 index 0000000..286e90f --- /dev/null +++ b/devops/templates/nginx.conf.j2 @@ -0,0 +1,27 @@ +# Nginx server configuration for a Next.js application +server { + listen 80; # Listen on port 80 (HTTP) + server_name {{ DOMAIN_NAME }}; + # Proxy requests to the Next.js server + location / { + # Pass requests to the Next.js server running on localhost:3000 + proxy_pass http://localhost:3001; + + # Proxy settings to handle WebSockets and HTTP/1.1 + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + + # Additional proxy headers + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Error handling and redirects + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + } +}