Jump to content

Setting Up CI/CD Pipeline for Go Applications: Simple Step-by-Step Guide


Gani
 Share

Recommended Posts

  • Moderators

📌 What is CI/CD?

  • CI = Continuous Integration: Automatically test/build code when you push changes

  • CD = Continuous Deployment: Automatically deploy to server when tests pass

Step 1: Choose Your CI/CD Tool

Popular Free Options:

  1. GitHub Actions (if using GitHub)

  2. GitLab CI/CD (if using GitLab)

  3. CircleCI (free tier available)

  4. Jenkins (self-hosted, more complex)

We'll use GitHub Actions for this guide (most beginner-friendly)

 

Step 2: Prepare Your Repository

2.1 Structure Your Project Properly

my-go-app/
├── main.go
├── go.mod
├── go.sum
├── README.md
├── .github/
│   └── workflows/
│       └── ci-cd.yml     # GitHub Actions file
├── tests/
│   └── main_test.go
└── scripts/
    └── deploy.sh

 

2.2 Create Test Files

 

// tests/main_test.go - Example test
package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestHandler(t *testing.T) {
    req, err := http.NewRequest("GET", "/", nil)
    if err != nil {
        t.Fatal(err)
    }
    
    rr := httptest.NewRecorder()
    handler := http.HandlerFunc(yourHandlerFunction)
    
    handler.ServeHTTP(rr, req)
    
    if status := rr.Code; status != http.StatusOK {
        t.Errorf("Expected status 200, got %v", status)
    }
}

 

Step 3: Set Up GitHub Actions CI/CD

 

3.1 Create Workflow File

 

In your repo, create: .github/workflows/ci-cd.yml

name: Go CI/CD Pipeline

on:
  push:
    branches: [ main, master ]
  pull_request:
    branches: [ main, master ]

jobs:
  # Job 1: Test and Build
  test-and-build:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: '1.21'
        
    - name: Install dependencies
      run: go mod download
      
    - name: Run tests
      run: go test ./... -v
      
    - name: Build for Linux
      run: GOOS=linux GOARCH=amd64 go build -o myapp ./main.go
      
    - name: Upload build artifact
      uses: actions/upload-artifact@v3
      with:
        name: go-binary
        path: myapp
        retention-days: 5

  # Job 2: Deploy to Server (only on main branch)
  deploy:
    runs-on: ubuntu-latest
    needs: test-and-build  # Wait for test job to pass
    if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
    
    steps:
    - name: Download build artifact
      uses: actions/download-artifact@v3
      with:
        name: go-binary
        
    - name: Make binary executable
      run: chmod +x myapp
      
    - name: Deploy to Server
      uses: appleboy/scp-action@master
      with:
        host: ${{ secrets.SERVER_HOST }}
        username: ${{ secrets.SERVER_USER }}
        password: ${{ secrets.SERVER_PASSWORD }}
        # or use key: ${{ secrets.SSH_PRIVATE_KEY }}
        port: 22
        source: "myapp"
        target: "/home/deploy/myapp"
        
    - name: Restart Service on Server
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.SERVER_HOST }}
        username: ${{ secrets.SERVER_USER }}
        password: ${{ secrets.SERVER_PASSWORD }}
        # or use key: ${{ secrets.SSH_PRIVATE_KEY }}
        port: 22
        script: |
          cd /home/deploy
          sudo systemctl restart myapp
          echo "Deployment completed!"

Step 4: Configure Secrets in GitHub

 

4.1 Add Repository Secrets

In your GitHub repo:

  1. Go to Settings  Secrets and variables  Actions

  2. Click New repository secret

  3. Add these secrets:

SERVER_HOST: your-server-ip-address
SERVER_USER: your-username
SERVER_PASSWORD: your-password
# OR use SSH key (more secure)
# SSH_PRIVATE_KEY: (paste your private key here)

 

4.2 Generate SSH Key (More Secure Option)

ssh-keygen -t rsa -b 4096 -C "github-actions"
# Don't add passphrase for automation
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

 

Copy private key to GitHub secrets:

cat ~/.ssh/id_rsa

Step 5: Prepare Your Server for Deployment

 

5.1 Create Deployment User

# Create a dedicated user for deployments
sudo adduser deploy
sudo usermod -aG sudo deploy  # Give sudo if needed

# Or better: limit to specific commands
sudo visudo
# Add: deploy ALL=(ALL) NOPASSWD: /bin/systemctl restart myapp

5.2 Set Up Directory Structure

sudo mkdir -p /var/www/myapp
sudo chown -R deploy:deploy /var/www/myapp

5.3 Create systemd Service (if not already)

sudo nano /etc/systemd/system/myapp.service

[Unit]
Description=My Go App
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/var/www/myapp
ExecStart=/var/www/myapp/myapp
Restart=always
Environment="PORT=8080"
Environment="DB_HOST=localhost"
# Add other env variables

[Install]
WantedBy=multi-user.target

Enable it:

sudo systemctl enable myapp

Step 6: Enhanced Pipeline with Docker (Optional)

 

6.1 Create Dockerfile

# Dockerfile
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN go mod download
RUN GOOS=linux GOARCH=amd64 go build -o main ./main.go

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

6.2 Update CI/CD for Docker

# Add to your workflow file
- name: Build Docker image
  run: docker build -t myapp:latest .
  
- name: Push to Docker Hub (optional)
  run: |
    echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
    docker tag myapp:latest username/myapp:${{ github.sha }}
    docker push username/myapp:${{ github.sha }}

Step 7: Advanced Pipeline Features

 

7.1 Multi-Stage Builds for Different Environments

# In your workflow file
jobs:
  # ... test and build steps ...

  deploy-staging:
    runs-on: ubuntu-latest
    needs: test-and-build
    if: github.ref == 'refs/heads/develop'
    environment: staging
    steps:
      # Deploy to staging server
      - run: echo "Deploying to staging..."
      
  deploy-production:
    runs-on: ubuntu-latest
    needs: test-and-build
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      # Deploy to production server
      - run: echo "Deploying to production..."
      # Add manual approval step if needed

7.2 Add Linting and Code Quality

- name: Run golangci-lint
  uses: golangci/golangci-lint-action@v3
  with:
    version: latest
    args: --timeout=5m

7.3 Database Migrations

 

Create a migration step:

- name: Run Database Migrations
  uses: appleboy/ssh-action@master
  with:
    host: ${{ secrets.SERVER_HOST }}
    username: ${{ secrets.SERVER_USER }}
    script: |
      cd /var/www/myapp
      ./migrate up

Step 8: Create Deployment Scripts

 

8.1 Server-side Deployment Script

#!/bin/bash
# scripts/deploy.sh

set -e  # Exit on error

echo "Starting deployment..."

# Backup current version
if [ -f myapp ]; then
    cp myapp myapp.backup.$(date +%Y%m%d%H%M%S)
fi

# Stop service
sudo systemctl stop myapp || true

# Replace binary
mv myapp.new myapp
chmod +x myapp

# Run database migrations if needed
# ./migrate up

# Start service
sudo systemctl start myapp

echo "Deployment completed successfully!"

8.2 Update GitHub Actions to Use Script

- name: Deploy using script
  uses: appleboy/ssh-action@master
  with:
    host: ${{ secrets.SERVER_HOST }}
    username: ${{ secrets.SERVER_USER }}
    script: |
      cd /home/deploy
      mv myapp myapp.new
      chmod +x scripts/deploy.sh
      ./scripts/deploy.sh

Step 9: Monitor Your Pipeline

 

9.1 Check Pipeline Status

  1. Go to your GitHub repo

  2. Click Actions tab

  3. See all workflow runs

  4. Click on a run to see details

 

9.2 Add Notifications

# Add to end of workflow
- name: Notify on Success
  if: success()
  run: |
    # Send to Slack/Discord/Email
    echo "Deployment successful!"
    
- name: Notify on Failure
  if: failure()
  run: |
    echo "Deployment failed!"
    # Send alert

Step 10: Testing Your Pipeline

 

10.1 Make a Test Commit

# Make a small change
echo "// test" >> main.go
git add .
git commit -m "Test CI/CD pipeline"
git push origin main

10.2 Watch It Run

  1. Go to GitHub → Actions

  2. Watch the pipeline execute

  3. Check server: sudo systemctl status myapp

 

📊 Simple vs Advanced Pipeline

Simple Pipeline (Start Here):

  1. Test code on push

  2. Build Go binary

  3. Copy to server

  4. Restart service

Advanced Pipeline (Add Later):

  1. Linting and code analysis

  2. Unit tests + Integration tests

  3. Build Docker image

  4. Push to registry

  5. Deploy to staging

  6. Manual approval step

  7. Deploy to production

  8. Run smoke tests

  9. Rollback if tests fail


🔧 Troubleshooting Common Issues

"Permission denied" on server

# On server:
sudo chown -R deploy:deploy /var/www/myapp
sudo chmod +x /var/www/myapp/myapp

 

SSH connection fails

  • Check firewall: sudo ufw status

  • Verify SSH is running: sudo systemctl status ssh

  • Test connection manually first

Tests fail in pipeline

  • Run tests locally first: go test ./...

  • Check Go version matches

  • Verify test dependencies


🎯 Best Practices

  1. Start simple - Basic CI first, add CD later

  2. Use secrets - Never hardcode credentials

  3. Test thoroughly - More tests = fewer production issues

  4. Implement rollbacks - Always have a way to revert

  5. Monitor deployments - Check logs after each deploy

  6. Use tags/versions - Deploy specific versions, not just "latest"

  7. Limit deployment access - Use deploy user, not root


📝 Quick Start Checklist

  • GitHub repo with Go code

  • Tests passing locally

  • .github/workflows/ci-cd.yml created

  • GitHub secrets configured

  • Server prepared with service file

  • Push code to trigger pipeline

  • Verify deployment works

That's it! Your Go application now has an automated CI/CD pipeline. Every time you push code, it automatically tests, builds, and deploys. Start with the simple version and add complexity as you grow!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

Terms of Use