Moderators Gani Posted January 14 Moderators Share Posted January 14 📌 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: GitHub Actions (if using GitHub) GitLab CI/CD (if using GitLab) CircleCI (free tier available) 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: Go to Settings → Secrets and variables → Actions Click New repository secret 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 Go to your GitHub repo Click Actions tab See all workflow runs 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 Go to GitHub → Actions Watch the pipeline execute Check server: sudo systemctl status myapp 📊 Simple vs Advanced Pipeline Simple Pipeline (Start Here): Test code on push Build Go binary Copy to server Restart service Advanced Pipeline (Add Later): Linting and code analysis Unit tests + Integration tests Build Docker image Push to registry Deploy to staging Manual approval step Deploy to production Run smoke tests 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 Start simple - Basic CI first, add CD later Use secrets - Never hardcode credentials Test thoroughly - More tests = fewer production issues Implement rollbacks - Always have a way to revert Monitor deployments - Check logs after each deploy Use tags/versions - Deploy specific versions, not just "latest" 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! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.