256. Instalasi Go di Windows (PC Baru)
Panduan lengkap instalasi Go di Windows dari nol: download, setup PATH, verifikasi, dan konfigurasi editor VS Code.
Instalasi Go di Windows — Langkah Demi Langkah
Berikut panduan lengkap untuk menjalankan Go di PC Windows yang masih bersih (fresh install), tanpa asumsi apapun.
Download Installer Resmi Go
Kunjungi https://go.dev/dl/ dan download file .msi terbaru untuk Windows (misal: go1.26.0.windows-amd64.msi).
Pilih versi amd64 untuk PC 64-bit (hampir semua PC modern). Jika PC Anda 32-bit, pilih versi 386.
Jalankan Installer MSI
Klik dua kali file .msi yang sudah didownload. Ikuti wizard instalasi (Next → Next → Install). Secara default Go akan diinstall ke C:\Program Files\Go.
Verifikasi Instalasi
Buka Command Prompt atau PowerShell baru (penting: buka yang baru agar PATH ter-refresh), lalu jalankan:
go version # Output: go version go1.26.0 windows/amd64 go env GOPATH # Output: C:\Users\NamaUser\go go env GOROOT # Output: C:\Program Files\Go
Buat Project Pertama
mkdir C:\Projects\hello-go
cd C:\Projects\hello-go
go mod init hello-go
echo package main > main.go
echo. >> main.go
echo import "fmt" >> main.go
echo. >> main.go
echo func main() { >> main.go
echo fmt.Println("Hello, Go Windows!") >> main.go
echo } >> main.go
go run main.go
# Output: Hello, Go Windows!
Setup VS Code untuk Go
Install VS Code dari https://code.visualstudio.com, lalu install extension Go by Google dari Marketplace. Buka folder project, tekan F5 untuk run & debug otomatis.
GOROOT=C:\Program Files\Go— Lokasi toolchain/SDK GoGOPATH=C:\Users\[User]\go— Workspace Go (bin, pkg, src)GOPATH\bin— Folder binary tools Go (gofmt, gopls, dll) — tambahkan ke PATH!
Contoh program
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println("=== Info Environment Go ===")
fmt.Println("Versi Go:", runtime.Version())
fmt.Println("Sistem Operasi:", runtime.GOOS)
fmt.Println("Arsitektur CPU:", runtime.GOARCH)
fmt.Println("Jumlah CPU Core:", runtime.NumCPU())
fmt.Println()
fmt.Println("Go berhasil berjalan di sistem Anda!")
}
257. Instalasi Go di Linux / Ubuntu
Instalasi Go di Ubuntu/Debian dari awal — via apt, manual tarball, dan update-alternatives untuk multi-versi.
Instalasi Go di Linux Ubuntu / Debian
Ada dua cara instalasi Go di Linux: via apt (mudah tapi versi bisa ketinggalan) atau manual tarball (recommended, selalu versi terbaru).
Metode 1: Manual Tarball (RECOMMENDED)
# 1. Hapus Go lama jika ada sudo rm -rf /usr/local/go # 2. Download Go terbaru (cek versi di https://go.dev/dl/) wget https://go.dev/dl/go1.26.0.linux-amd64.tar.gz # 3. Ekstrak ke /usr/local sudo tar -C /usr/local -xzf go1.26.0.linux-amd64.tar.gz # 4. Tambahkan Go ke PATH — edit ~/.bashrc atau ~/.zshrc echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc echo 'export GOPATH=$HOME/go' >> ~/.bashrc echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.bashrc # 5. Reload konfigurasi shell source ~/.bashrc # 6. Verifikasi go version # go version go1.26.0 linux/amd64
Metode 2: Via apt (Ubuntu 22.04+)
sudo apt update sudo apt install golang-go -y go version # Catatan: versi mungkin lebih lama dari upstream
Package golang-go di repository apt Ubuntu seringkali tertinggal beberapa versi dari upstream resmi Go. Untuk production, gunakan metode tarball agar mendapat versi terbaru.
Membuat Project Pertama di Linux
mkdir ~/projects/hello-go && cd ~/projects/hello-go
go mod init hello-go
cat > main.go << 'EOF'
package main
import "fmt"
func main() {
fmt.Println("Hello dari Go di Linux!")
}
EOF
go run main.go
# Output: Hello dari Go di Linux!
Build Binary untuk Production
# Build binary executable go build -o hello-app main.go # Jalankan binary ./hello-app # Build untuk platform lain (cross-compile) GOOS=windows GOARCH=amd64 go build -o hello-app.exe main.go GOOS=darwin GOARCH=amd64 go build -o hello-app-mac main.go
Contoh program
package main
import (
"fmt"
"runtime"
"os"
)
func main() {
fmt.Println("=== System Info dari Go ===")
fmt.Println("OS:", runtime.GOOS)
fmt.Println("ARCH:", runtime.GOARCH)
fmt.Println("Go Version:", runtime.Version())
fmt.Println("CPU Count:", runtime.NumCPU())
fmt.Println("Hostname:", getHostname())
}
func getHostname() string {
hostname, err := os.Hostname()
if err != nil {
return "unknown"
}
return hostname
}
258. Menjalankan Go App di VPS / Ubuntu Server
Setup Go di server Ubuntu dari nol: SSH ke VPS, install Go, deploy binary, dan jalankan sebagai background process.
Deploy Aplikasi Go ke VPS Ubuntu
Skenario: Anda memiliki VPS Ubuntu (misal dari DigitalOcean, Vultr, AWS Lightsail) dan ingin menjalankan aplikasi Go di sana.
Koneksi SSH ke VPS
ssh root@IP_SERVER_ANDA # atau dengan SSH key: ssh -i ~/.ssh/id_rsa ubuntu@IP_SERVER_ANDA
Update Server & Install Go
sudo apt update && sudo apt upgrade -y wget https://go.dev/dl/go1.26.0.linux-amd64.tar.gz sudo tar -C /usr/local -xzf go1.26.0.linux-amd64.tar.gz echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc source ~/.bashrc go version
Upload & Build Aplikasi
# Upload source code ke VPS scp -r ./my-go-app ubuntu@IP_SERVER:/home/ubuntu/ # Atau build di lokal dulu, upload binary GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o my-app main.go scp my-app ubuntu@IP_SERVER:/home/ubuntu/
cd /home/ubuntu/my-go-app go build -o my-app main.go chmod +x my-app ./my-app
Jalankan sebagai Background Process
# Jalankan di background, abaikan HUP signal nohup ./my-app > /var/log/my-app.log 2>&1 & # Cek apakah berjalan ps aux | grep my-app # Lihat log tail -f /var/log/my-app.log
Untuk deployment produksi yang proper, gunakan systemd service (lihat bab berikutnya) agar app otomatis restart jika crash dan berjalan saat server reboot.
Konfigurasi Firewall (UFW)
# Izinkan port aplikasi Go (misal port 8080) sudo ufw allow 8080/tcp sudo ufw enable sudo ufw status
Contoh program
package main
import (
"fmt"
"net/http"
"log"
)
// Simple HTTP server untuk di-deploy ke VPS
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello dari Go Server!\nMethod: %s\nPath: %s\n",
r.Method, r.URL.Path)
})
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, `{"status": "ok", "service": "go-app"}`)
})
fmt.Println("Server berjalan di :8080")
fmt.Println("Akses: http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
259. Deploy Go dengan systemd Service
Membuat systemd unit file untuk aplikasi Go agar otomatis berjalan saat boot, auto-restart jika crash, dan manajemen log terpusat.
Mengapa systemd untuk Go App?
systemd adalah init system standar di Ubuntu/Debian modern. Dengan systemd, aplikasi Go Anda akan:
- ✅ Auto-start saat server reboot
- ✅ Auto-restart jika crash (Restart=on-failure)
- ✅ Log terpusat via journalctl
- ✅ Manajemen mudah: start/stop/restart/status via systemctl
Siapkan Binary & Direktori
# Buat direktori untuk aplikasi sudo mkdir -p /opt/my-go-app # Copy binary ke sana sudo cp ./my-app /opt/my-go-app/ sudo chmod +x /opt/my-go-app/my-app # Buat user dedicated (best practice keamanan) sudo useradd -r -s /bin/false goapp
Buat systemd Unit File
sudo nano /etc/systemd/system/my-go-app.service
[Unit] Description=My Go Application Server Documentation=https://github.com/yourname/my-go-app After=network.target [Service] Type=simple User=goapp Group=goapp WorkingDirectory=/opt/my-go-app ExecStart=/opt/my-go-app/my-app Restart=on-failure RestartSec=5s StandardOutput=journal StandardError=journal SyslogIdentifier=my-go-app Environment=PORT=8080 Environment=GIN_MODE=release [Install] WantedBy=multi-user.target
Aktifkan & Jalankan Service
# Reload systemd untuk membaca unit file baru sudo systemctl daemon-reload # Enable agar auto-start saat boot sudo systemctl enable my-go-app # Start service sekarang sudo systemctl start my-go-app # Cek status sudo systemctl status my-go-app # Lihat log real-time sudo journalctl -u my-go-app -f # Stop service sudo systemctl stop my-go-app # Restart service sudo systemctl restart my-go-app
Saat ada update binary: build baru → stop service → copy binary → start service lagi.
sudo systemctl stop my-go-app sudo cp ./new-app /opt/my-go-app/my-app sudo systemctl start my-go-app
Contoh program
package main
import (
"fmt"
"net/http"
"log"
"os"
"os/signal"
"syscall"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.HandleFunc("/", homeHandler)
http.HandleFunc("/health", healthHandler)
// Graceful shutdown
go func() {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
log.Println("Server shutting down gracefully...")
os.Exit(0)
}()
log.Printf("Server berjalan di port %s", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Go App berjalan! (systemd service)")
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, `{"status":"healthy"}`)
}
260. Dockerize Aplikasi Go — Dockerfile Dasar
Membuat Dockerfile untuk aplikasi Go, build image, run container, dan memahami layer caching Docker.
Mengapa Docker untuk Go?
Docker memungkinkan Anda mengemas aplikasi Go beserta seluruh dependensinya dalam sebuah container yang berjalan identik di manapun — laptop developer, staging server, maupun production cloud.
- Image: Blueprint/template container (dari Dockerfile)
- Container: Instance yang berjalan dari sebuah image
- Layer: Setiap instruksi Dockerfile membuat layer yang di-cache
- Registry: Tempat penyimpanan image (Docker Hub, ECR, GCR)
Struktur Project
my-go-app/ ├── main.go ├── go.mod ├── go.sum └── Dockerfile
Dockerfile — Versi Sederhana
# Base image dengan Go toolchain FROM golang:1.26-alpine # Set working directory di dalam container WORKDIR /app # Copy dependency files dulu (untuk layer caching) COPY go.mod go.sum ./ RUN go mod download # Copy seluruh source code COPY . . # Build binary RUN go build -o my-app main.go # Expose port yang digunakan aplikasi EXPOSE 8080 # Perintah yang dijalankan saat container start CMD ["./my-app"]
Build & Run Container
# Build Docker image docker build -t my-go-app:latest . # Lihat image yang sudah dibuat docker images # Jalankan container (port 8080 host → 8080 container) docker run -d -p 8080:8080 --name go-server my-go-app:latest # Cek container berjalan docker ps # Lihat log container docker logs -f go-server # Stop & remove container docker stop go-server && docker rm go-server
Dockerfile sederhana di atas menggunakan golang:alpine sebagai base image final, yang masih mengandung seluruh Go toolchain. Ukuran image bisa 300-400 MB. Solusi: Multi-Stage Build (lihat bab berikutnya).
Contoh program
package main
import (
"fmt"
"net/http"
"log"
"os"
)
// Aplikasi ini akan di-Dockerize
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
host, _ := os.Hostname()
fmt.Fprintf(w, "Hello dari Docker Container!\nContainer ID: %s\nPort: %s\n",
host, port)
})
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, `{"status":"ok","runtime":"go-docker"}`)
})
log.Printf("🐳 Docker Go Server running on :%s", port)
log.Fatal(http.ListenAndServe(":"+port, mux))
}
261. Multi-Stage Docker Build untuk Go
Optimasi Docker image Go dari 400MB menjadi <15MB menggunakan Multi-Stage Build dengan builder + distroless/scratch.
Masalah dengan Single-Stage Dockerfile
Dockerfile satu tahap menghasilkan image yang berisi seluruh Go toolchain (compiler, standard library, tools), padahal untuk menjalankan binary Go, Anda hanya butuh binarynya saja.
- ❌ Single-stage (golang:alpine): ~350-400 MB
- ✅ Multi-stage (scratch): ~8-15 MB
- ✅ Multi-stage (distroless): ~20-30 MB
Multi-Stage Dockerfile — Versi Scratch (Paling Kecil)
# ── Stage 1: Builder ──
FROM golang:1.26-alpine AS builder
WORKDIR /build
# Install dependencies
COPY go.mod go.sum ./
RUN go mod download
# Copy & build dengan optimasi
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build \
-ldflags="-s -w -extldflags=-static" \
-o app main.go
# ── Stage 2: Final Image ──
# Gunakan scratch (image kosong, 0 byte)
FROM scratch
# Copy hanya binary dari stage builder
COPY --from=builder /build/app /app
# Copy SSL certificates (untuk HTTPS calls)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# Expose port
EXPOSE 8080
# Jalankan binary
ENTRYPOINT ["/app"]
Multi-Stage dengan distroless (Lebih Aman)
FROM golang:1.26-alpine AS builder WORKDIR /build COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o app main.go # Google Distroless: punya user non-root, certs, tzdata FROM gcr.io/distroless/static:nonroot COPY --from=builder /build/app /app EXPOSE 8080 USER nonroot:nonroot ENTRYPOINT ["/app"]
docker build -t my-go-app:optimized . docker images | grep my-go-app # REPOSITORY TAG SIZE # my-go-app optimized 12.4MB ← jauh lebih kecil!
CGO_ENABLED=0 menonaktifkan cgo (C bindings), menghasilkan binary yang pure Go dan fully static — tidak bergantung pada shared library C di sistem operasi. Wajib jika menggunakan image scratch.
Contoh program
package main
import (
"fmt"
"net/http"
"log"
"runtime"
)
// Aplikasi siap untuk Multi-Stage Docker Build
// Binary yang dihasilkan: fully static, ~8MB
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{
"message": "Go App berjalan dalam container!",
"go_version": "%s",
"os": "%s",
"arch": "%s"
}`, runtime.Version(), runtime.GOOS, runtime.GOARCH)
})
log.Println("Multi-stage Go Docker container ready: :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
262. Docker Compose untuk Go App
Menjalankan Go app bersama database (PostgreSQL/Redis) menggunakan Docker Compose dengan networking, volumes, dan environment variables.
Docker Compose: Multi-Container Setup
Docker Compose memungkinkan Anda mendefinisikan dan menjalankan aplikasi multi-container dalam satu file konfigurasi YAML. Ideal untuk Go app + database + cache.
version: '3.9'
services:
# ── Go Application ──
app:
build:
context: .
dockerfile: Dockerfile
container_name: go-app
ports:
- "8080:8080"
environment:
- DB_HOST=postgres
- DB_PORT=5432
- DB_USER=gouser
- DB_PASS=secretpass
- DB_NAME=myapp
- REDIS_URL=redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
networks:
- app-network
restart: unless-stopped
# ── PostgreSQL Database ──
postgres:
image: postgres:16-alpine
container_name: go-postgres
environment:
POSTGRES_USER: gouser
POSTGRES_PASSWORD: secretpass
POSTGRES_DB: myapp
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gouser -d myapp"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
# ── Redis Cache ──
redis:
image: redis:8-alpine
container_name: go-redis
volumes:
- redis_data:/data
networks:
- app-network
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge
Perintah Docker Compose
# Jalankan semua service (build jika perlu) docker compose up -d # Rebuild & restart hanya service app docker compose up -d --build app # Lihat status semua service docker compose ps # Lihat log semua service docker compose logs -f # Lihat log service spesifik docker compose logs -f app # Stop semua service docker compose down # Stop + hapus volumes docker compose down -v
Gunakan condition: service_healthy bersama healthcheck agar Go app menunggu database benar-benar siap (bukan hanya containernya yang started).
Contoh program
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"os"
// Simulasi struktur yang akan digunakan dengan PostgreSQL
)
type Config struct {
DBHost string
DBPort string
DBUser string
DBPassword string
DBName string
}
func getConfig() Config {
return Config{
DBHost: getEnv("DB_HOST", "localhost"),
DBPort: getEnv("DB_PORT", "5432"),
DBUser: getEnv("DB_USER", "postgres"),
DBPassword: getEnv("DB_PASS", "password"),
DBName: getEnv("DB_NAME", "myapp"),
}
}
func getEnv(key, defaultVal string) string {
if val := os.Getenv(key); val != "" {
return val
}
return defaultVal
}
func getDBConnectionString(cfg Config) string {
return fmt.Sprintf(
"host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
cfg.DBHost, cfg.DBPort, cfg.DBUser, cfg.DBPassword, cfg.DBName,
)
}
func main() {
cfg := getConfig()
connStr := getDBConnectionString(cfg)
fmt.Println("Connection string:", connStr)
// Di production, uncomment ini:
// db, err := sql.Open("postgres", connStr)
_ = sql.ErrNoRows // prevent unused import
http.HandleFunc("/config", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "DB: %s@%s:%s/%s", cfg.DBUser, cfg.DBHost, cfg.DBPort, cfg.DBName)
})
log.Println("App siap. DB config loaded dari environment.")
log.Fatal(http.ListenAndServe(":8080", nil))
}
263. Nginx sebagai Reverse Proxy untuk Go
Konfigurasi Nginx sebagai reverse proxy di depan Go app: load balancing, SSL termination, static file serving, dan security headers.
Arsitektur: Nginx + Go App
Dalam production, sangat umum meletakkan Nginx di depan Go app sebagai reverse proxy. Nginx menangani:
- 🔒 SSL/TLS termination (HTTPS)
- ⚡ Static file serving (CSS, JS, images)
- ⚖️ Load balancing ke multiple Go instances
- 🛡️ Security headers, rate limiting
- 📝 Access logging terpusat
sudo apt install nginx -y sudo systemctl enable nginx sudo systemctl start nginx
Konfigurasi Nginx sebagai Reverse Proxy
upstream go_backend {
server 127.0.0.1:8080;
# Load balancing ke multiple instances:
# server 127.0.0.1:8081;
# server 127.0.0.1:8082;
}
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# Redirect HTTP ke HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL Certificates (via Certbot)
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
# Static files served directly by Nginx
location /static/ {
alias /opt/my-go-app/static/;
expires 30d;
}
# Proxy semua request lain ke Go app
location / {
proxy_pass http://go_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 86400;
}
}
# Buat symlink ke sites-enabled sudo ln -s /etc/nginx/sites-available/my-go-app /etc/nginx/sites-enabled/ # Test konfigurasi Nginx sudo nginx -t # Reload Nginx sudo systemctl reload nginx # Install SSL via Certbot (free Let's Encrypt) sudo apt install certbot python3-certbot-nginx -y sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Dengan proxy_set_header X-Real-IP $remote_addr, Go app bisa mendapatkan IP address asli client (bukan IP Nginx) melalui r.Header.Get("X-Real-IP").
Contoh program
package main
import (
"fmt"
"net/http"
"log"
)
// Go app yang di-proxy oleh Nginx
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Dapatkan IP asli client dari header Nginx
realIP := r.Header.Get("X-Real-IP")
if realIP == "" {
realIP = r.RemoteAddr
}
proto := r.Header.Get("X-Forwarded-Proto")
if proto == "" {
proto = "http"
}
fmt.Fprintf(w, "Request diterima!\nClient IP: %s\nProtocol: %s\nHost: %s\nPath: %s",
realIP, proto, r.Host, r.URL.Path)
})
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, `{"status":"ok"}`)
})
// Go app hanya listen di localhost (Nginx yang expose ke internet)
log.Println("Go backend berjalan di :8080 (behind Nginx)")
log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
}
264. CI/CD Dasar untuk Go dengan GitHub Actions
Otomasi build, test, dan deploy aplikasi Go menggunakan GitHub Actions workflow — dari push code hingga deploy otomatis ke server.
CI/CD untuk Go App
CI/CD (Continuous Integration / Continuous Deployment) mengotomasi proses: setiap kali push code ke GitHub, pipeline secara otomatis menjalankan test, build, dan deploy aplikasi.
Struktur Direktori GitHub Actions
my-go-app/ ├── .github/ │ └── workflows/ │ ├── ci.yml ← Test & Build (setiap push/PR) │ └── deploy.yml ← Deploy ke server (saat merge ke main) ├── main.go ├── main_test.go └── Dockerfile
Workflow CI — Test & Build
name: Go CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
name: Test & Build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.26'
cache: true
- name: Download dependencies
run: go mod download
- name: Run vet
run: go vet ./...
- name: Run tests
run: go test -v -race -coverprofile=coverage.txt ./...
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
file: ./coverage.txt
- name: Build binary
run: |
CGO_ENABLED=0 GOOS=linux go build \
-ldflags="-s -w" \
-o my-app ./...
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: go-binary
path: my-app
Workflow Deploy — SSH ke VPS
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
needs: test # Hanya deploy jika CI berhasil
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
with:
go-version: '1.26'
- name: Build
run: CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o my-app .
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
systemctl stop my-go-app
cp /opt/backup/my-app /opt/backup/my-app.prev
- name: Upload binary
uses: appleboy/scp-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
source: "my-app"
target: "/opt/my-go-app/"
- name: Restart service
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: systemctl start my-go-app
Simpan credential sensitif (SSH key, server IP) di GitHub → Settings → Secrets and Variables → Actions. Jangan pernah hardcode di file workflow!
Contoh program
package main
import (
"fmt"
"testing"
)
// Fungsi yang akan ditest dalam CI/CD pipeline
func add(a, b int) int {
return a + b
}
func multiply(a, b int) int {
return a * b
}
// Test functions (file ini biasanya di main_test.go)
func TestAdd(t *testing.T) {
result := add(3, 4)
if result != 7 {
t.Errorf("add(3, 4) = %d, want 7", result)
}
}
func TestMultiply(t *testing.T) {
cases := []struct {
a, b, expected int
}{
{2, 3, 6},
{0, 5, 0},
{-1, 4, -4},
}
for _, tc := range cases {
result := multiply(tc.a, tc.b)
if result != tc.expected {
t.Errorf("multiply(%d, %d) = %d, want %d",
tc.a, tc.b, result, tc.expected)
}
}
}
func main() {
fmt.Println("go test ./... menjalankan semua test otomatis")
fmt.Println("CI/CD memastikan kode ter-test setiap push ke GitHub")
fmt.Println("add(10, 20) =", add(10, 20))
}