GitLab CI/CD Best Practices untuk Golang Projects

4 min read
#cicd #gitlab #devops #golang #docker

Dalam membangun dan maintain aplikasi Go di production, CI/CD pipeline yang baik adalah essential. Berikut adalah best practices yang saya implementasikan di berbagai projects.

1. Basic Pipeline Structure

# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

variables:
  GO_VERSION: "1.21"
  DOCKER_REGISTRY: "registry.gitlab.com"

before_script:
  - echo "Starting pipeline for $CI_COMMIT_REF_NAME"

test:
  stage: test
  image: golang:${GO_VERSION}
  script:
    - go mod download
    - go test -v -race -coverprofile=coverage.out ./...
    - go tool cover -func=coverage.out
  coverage: '/total:\s+\(statements\)\s+(\d+\.\d+)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.out

lint:
  stage: test
  image: golangci/golangci-lint:latest
  script:
    - golangci-lint run -v
  allow_failure: false

2. Multi-Stage Docker Build

Optimasi Docker image size sangat penting untuk deployment speed:

# Dockerfile
# Build stage
FROM golang:1.21-alpine AS builder

WORKDIR /app

# Copy go mod files
COPY go.mod go.sum ./
RUN go mod download

# Copy source code
COPY . .

# Build binary
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

# Runtime stage
FROM alpine:latest

RUN apk --no-cache add ca-certificates

WORKDIR /root/

# Copy binary from builder
COPY --from=builder /app/main .

EXPOSE 8080

CMD ["./main"]

Result: Image size dari 800MB menjadi 15MB 🎉

3. Build & Push Docker Image

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker push $CI_REGISTRY_IMAGE:latest
  only:
    - main
    - develop

4. Deploy ke Staging/Production

deploy:staging:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
  script:
    - ssh -o StrictHostKeyChecking=no $STAGING_USER@$STAGING_HOST "
        docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA &&
        docker stop api-staging || true &&
        docker rm api-staging || true &&
        docker run -d
          --name api-staging
          --restart always
          -p 8080:8080
          -e DATABASE_URL=$STAGING_DB_URL
          -e REDIS_URL=$STAGING_REDIS_URL
          $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      "
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

deploy:production:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
  script:
    - ssh -o StrictHostKeyChecking=no $PROD_USER@$PROD_HOST "
        docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA &&
        docker stop api-prod || true &&
        docker rm api-prod || true &&
        docker run -d
          --name api-prod
          --restart always
          -p 8080:8080
          -e DATABASE_URL=$PROD_DB_URL
          -e REDIS_URL=$PROD_REDIS_URL
          $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      "
  environment:
    name: production
    url: https://api.example.com
  when: manual
  only:
    - main

5. Caching untuk Speed Up

test:
  stage: test
  image: golang:1.21
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - .go/pkg/mod/
  before_script:
    - export GOPATH=$CI_PROJECT_DIR/.go
  script:
    - go mod download
    - go test ./...

Result: Build time dari 5 menit menjadi 1.5 menit

6. Security Scanning

security:trivy:
  stage: test
  image: aquasec/trivy:latest
  script:
    - trivy image --exit-code 0 --severity LOW,MEDIUM $CI_REGISTRY_IMAGE:latest
    - trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:latest
  allow_failure: false

security:gosec:
  stage: test
  image: securego/gosec:latest
  script:
    - gosec ./...
  allow_failure: true

7. Database Migrations

migrate:
  stage: deploy
  image: migrate/migrate
  script:
    - migrate -path ./migrations -database "$DATABASE_URL" up
  only:
    - main
  when: manual

8. Rollback Strategy

rollback:production:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client git
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
  script:
    - PREVIOUS_SHA=$(git rev-parse HEAD~1)
    - ssh -o StrictHostKeyChecking=no $PROD_USER@$PROD_HOST "
        docker pull $CI_REGISTRY_IMAGE:$PREVIOUS_SHA &&
        docker stop api-prod &&
        docker rm api-prod &&
        docker run -d
          --name api-prod
          --restart always
          -p 8080:8080
          $CI_REGISTRY_IMAGE:$PREVIOUS_SHA
      "
  environment:
    name: production
    action: rollback
  when: manual
  only:
    - main

Best Practices Summary

  1. Always run tests before deployment
  2. Use multi-stage Docker builds untuk optimize image size
  3. Cache dependencies untuk faster builds
  4. Implement security scanning di pipeline
  5. Manual approval untuk production deploys
  6. Always have rollback strategy
  7. Use environment variables untuk secrets
  8. Monitor pipeline metrics dan optimize bottlenecks

Real Impact

Di project Foxlogger, dengan implementasi CI/CD ini:

  • ✅ Deployment time: 20 menit3 menit
  • ✅ Zero-downtime deployments
  • ✅ Automatic rollback on failure
  • ✅ 100% test coverage enforcement
  • ✅ Security vulnerabilities caught before production

Kesimpulan

CI/CD yang baik bukan hanya tentang automation, tapi juga tentang safety, speed, dan confidence dalam shipping code to production.

Invest time di setup awal, dan Anda akan save hours setiap minggu! 🚀


Questions? Feel free to reach out!

Share this article

AS

Arian Saputra

Backend Engineer with 6+ years across BPM & distributed systems. Go, microservices, CI/CD, performance tuning.