Search the Community
Showing results for tags 'ci/cd'.
-
📌 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!
