I have experience where when we want to deploy our service should contact ops team. This is really takes time because sometimes those ops team very busy or need to contact ops team that takes time. So i think we should automate this to improve our SDLC. For this example i use github and github action to accomodate automation flow. Lest start.
-
First create github token that will we used in our runner. Runner means a ‘virtual machine’ that we used for run testing and build docker image. To access our repository and github action, the runner should have github token. For simplycity we can use personal access token
-
Put the token into repository secrets.
-
Create github action file to run unit test or integration test and build artifact.
# This workflow will build a golang project # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go name: Go on: push: tags: - "*" jobs: test: runs-on: ubuntu-latest services: dind: image: docker:23.0-rc-dind-rootless ports: - 2375:2375 steps: - name: Checkout Code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.21' - name: Test run: go test -v ./... build: needs: test runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v4 - name: Build and Push Image run: | docker login --username mnaufala13 --password ${{ secrets.GH_SECRET }} ghcr.io docker build . --tag ghcr.io/mnaufala13/learn-ci:${{ github.ref_name }} docker push ghcr.io/mnaufala13/learn-ci:${{ github.ref_name }}
-
Create new repository to save our script and config for the service.
0.0.13
-
Create script for deploy the service
#!/bin/bash # Check if three arguments are passed if [ "$#" -ne 4 ]; then echo "Usage: $0 <image> <container_name> <image_tar_path> <config_path>" exit 1 fi IMAGE=$1 CONTAINER_NAME=$2 IMAGE_TAR_PATH=$3 CONFIG_PATH=$4 # Step 1: Stop the container if it exists if docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}$"; then echo "Stopping existing container: $CONTAINER_NAME" docker stop "$CONTAINER_NAME" && docker rm "$CONTAINER_NAME" else echo "Container does not exist: $CONTAINER_NAME" fi # Step 2: Load the image from tar file echo "Loading image from: $IMAGE_TAR_PATH" docker load -i "$IMAGE_TAR_PATH" # Step 3: Run the container in the background echo "Starting container: $CONTAINER_NAME with image: $IMAGE" docker run -v "$CONFIG_PATH:/app/config.json" -d --name "$CONTAINER_NAME" "$IMAGE" # Step 4: Sleep for 5 seconds sleep 5 # Step 5: Print the last 10 lines of the container's logs echo "Displaying last 10 lines of logs for container: $CONTAINER_NAME" docker logs --tail 10 "$CONTAINER_NAME"
-
Insert the ssh user, host, token and github token to secret repository.
-
Create github action workflow to run our deployment script.
# This workflow will build a golang project # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go name: Deploy on: push: branches: ["main"] pull_request: branches: ["main"] jobs: Deploy: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v4 - name: Set SSH Key and Permission run: | mkdir -p ~/.ssh echo "${{ secrets.SSH_PRIV_KEY }}" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa - name: Upload Image and Config run: | VER=$( cat version.txt ) IMG="ghcr.io/mnaufala13/learn-ci:$VER" docker login --username mnaufala13 --password ${{ secrets.GH_SECRET }} ghcr.io docker pull $IMG docker image save $IMG > image.tar scp -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa image.tar config.json deploy.sh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/tmp/ - name: Load and Run Image run: | VER=$( cat version.txt ) IMG="ghcr.io/mnaufala13/learn-ci:$VER" ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "chmod +x /tmp/deploy.sh && /tmp/deploy.sh $IMG thor /tmp/image.tar /tmp/config.json"