Salin dan Bagikan
Hugo dan Docker: Containerization untuk Deployment Konsisten - Panduan lengkap containerization Hugo dengan Docker. Pelajari cara setup Docker environment, …

Hugo dan Docker: Containerization untuk Deployment Konsisten

Hugo dan Docker: Containerization untuk Deployment Konsisten

Docker telah menjadi standar industri untuk application containerization, memungkinkan development dan deployment yang konsisten across environments. Untuk Hugo sites, Docker dapat digunakan untuk create reproducible build environments, simplify deployment, dan enable modern DevOps practices. Panduan ini akan membahas cara mengintegrasikan Hugo dengan Docker untuk workflow development dan deployment yang efficient.

Docker memberikan konsistensi antara development dan production environments, eliminate “works on my machine” issues, dan simplify deployment ke berbagai platforms termasuk Kubernetes.

Docker Setup untuk Hugo

Dockerfile Dasar

# Dockerfile
FROM golang:1.21-alpine AS builder

# Install Hugo Extended
ARG HUGO_VERSION=0.139.2
RUN wget -O /tmp/hugo.tar.gz \
    https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_Linux-64bit.tar.gz \
    && tar -xzf /tmp/hugo.tar.gz \
    && mv hugo /usr/local/bin/ \
    && rm /tmp/hugo.tar.gz

# Set work directory
WORKDIR /app

# Copy source files
COPY . .

# Build Hugo site
RUN hugo --minify --environment production

# Use nginx for serving
FROM nginx:alpine

# Copy built files
COPY --from=builder /app/public /usr/share/nginx/html

# Copy nginx config
COPY nginx.conf /etc/nginx/nginx.conf

# Expose port
EXPOSE 80

# Health check
HEALTHCHECK --interval=30s --timeout=3s \
    CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1

CMD ["nginx", "-g", "daemon off;"]

Nginx Configuration untuk Docker

# nginx.conf
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    keepalive_timeout 65;
    gzip on;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    server {
        listen 80;
        server_name localhost;
        root /usr/share/nginx/html;
        index index.html;

        location / {
            try_files $uri $uri/ =404;
        }

        # Cache static assets
        location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }
}

Multi-Stage Builds

Optimized Multi-Stage Dockerfile

# syntax=docker/dockerfile:1
# ============
# Build Stage
# ============
FROM golang:1.21-alpine AS builder

# Install Hugo
ARG HUGO_VERSION=0.139.2
ENV HUGO_VERSION=${HUGO_VERSION}
RUN wget -q -O /tmp/hugo.tar.gz \
    https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_Linux-64bit.tar.gz \
    && tar -xf /tmp/hugo.tar.gz -C /tmp \
    && mv /tmp/hugo /usr/local/bin/hugo \
    && rm /tmp/hugo.tar.gz

# Install git untuk submodule
RUN apk add --no-cache git

WORKDIR /src

# Copy only necessary files first for better caching
COPY go.mod go.sum* ./
RUN go mod download && go mod verify

# Copy source
COPY . .

# Build dengan environment production
ENV HUGO_ENVIRONMENT=production
ENV HUGO_MINIFY=true

RUN hugo --gc --minify

# ============
# Production Stage
# ============
FROM nginx:alpine AS production

# Install security packages
RUN apk add --no-cache nginx-mod-http-geoip nginx-mod-http-image-filter \
    && apk add --no-cache curl

# Copy nginx configuration
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY nginx/conf.d /etc/nginx/conf.d

# Copy built Hugo site
COPY --from=builder /src/public /usr/share/nginx/html

# Create non-root user
RUN addgroup -g 1000 -S appgroup && \
    adduser -u 1000 -S appuser -G appgroup && \
    chown -R appuser:appgroup /usr/share/nginx/html && \
    chown -R appuser:appgroup /var/cache/nginx && \
    chown -R appuser:appgroup /var/log/nginx && \
    touch /var/run/nginx.pid && \
    chown -R appuser:appgroup /var/run/nginx.pid

USER appuser

EXPOSE 80

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost/health || exit 1

CMD ["nginx", "-g", "daemon off;"]

Development Environment dengan Docker

Docker Compose untuk Development

# docker-compose.yml
version: '3.8'

services:
  hugo:
    build:
      context: .
      dockerfile: Dockerfile.dev
    container_name: hugo-dev
    command: hugo server --bind 0.0.0.0 --port 1313 -D
    ports:
      - "1313:1313"
    volumes:
      - .:/src:cached
      - hugo_cache:/src/.hugo_cache
    environment:
      - HUGO_ENVIRONMENT=development
    networks:
      - hugo-network

  # Optional: Live reload dengan air
  hugo-air:
    build:
      context: .
      dockerfile: Dockerfile.air
    container_name: hugo-air
    ports:
      - "1314:1314"
    volumes:
      - .:/src:cached
    environment:
      - HUGO_ENV=development
    networks:
      - hugo-network

volumes:
  hugo_cache:

networks:
  hugo-network:
    driver: bridge

Dockerfile Development

# Dockerfile.dev
FROM golang:1.21-alpine

# Install Hugo
ARG HUGO_VERSION=0.139.2
RUN wget -O /tmp/hugo.tar.gz \
    https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_Linux-64bit.tar.gz \
    && tar -xzf /tmp/hugo.tar.gz -C /tmp \
    && mv /tmp/hugo /usr/local/bin/hugo \
    && rm /tmp/hugo.tar.gz

# Install git untuk submodule
RUN apk add --no-cache git

WORKDIR /src

# Expose port
EXPOSE 1313

CMD ["sh"]

Docker dengan GitHub Actions

Build dan Push Docker Image

# .github/workflows/docker.yml
name: Docker Build and Push

on:
  push:
    branches: [main]
    tags: ['v*']
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=tag
            type=raw,value=latest,enable={{is_default_branch}}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Docker untuk Multi-Platform Build

Build ARM dan AMD64

# docker-compose.ci.yml
services:
  builder:
    build:
      context: .
      dockerfile: Dockerfile
      platforms:
        - linux/amd64
        - linux/arm64
    image: hugo-builder:${TAG:-latest}

Kubernetes Deployment

Kubernetes Manifests

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hugo-site
  labels:
    app: hugo-site
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hugo-site
  template:
    metadata:
      labels:
        app: hugo-site
    spec:
      containers:
        - name: hugo
          image: ghcr.io/username/hugo-site:latest
          ports:
            - containerPort: 80
          resources:
            requests:
              memory: "64Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "200m"
          livenessProbe:
            httpGet:
              path: /health
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 30
          readinessProbe:
            httpGet:
              path: /health
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 10

---
apiVersion: v1
kind: Service
metadata:
  name: hugo-service
spec:
  selector:
    app: hugo-site
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hugo-ingress
  annotations:
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
spec:
  tls:
    - hosts:
        - example.com
      secretName: hugo-tls
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: hugo-service
                port:
                  number: 80

Docker Best Practices

Image Size Optimization

# Multi-stage build untuk minimize image size
FROM golang:1.21-alpine AS builder
# Build commands...

FROM nginx:alpine AS production
# Copy dari builder...
# Final image kecil dan efficient

Security Best Practices

# Use specific version, not 'latest'
FROM golang:1.21-alpine

# Create non-root user
RUN addgroup -g 1000 -S appgroup && \
    adduser -u 1000 -S appuser -G appgroup

USER appuser

# Don't run as root

Caching Strategy

# Copy go.mod pertama untuk leverage Docker cache
COPY go.mod go.sum* ./
RUN go mod download && go mod verify

# Copy source setelah dependencies
COPY . .

Troubleshooting Docker

Common Issues dan Solutions

# Check container logs
docker logs hugo-container

# Exec into container
docker exec -it hugo-container sh

# Check container resources
docker stats hugo-container

# Debug build issues
docker build --no-cache -t hugo-debug .

Kesimpulan

Docker containerization untuk Hugo sites memberikan konsistensi, portability, dan scalability. Dengan setup yang tepat, Anda dapat achieve reproducible builds dan simplified deployments across different environments.

Artikel Terkait

Link Postingan : https://www.tirinfo.com/hugo-docker/

Hendra WIjaya
Tirinfo
5 minutes.
4 February 2026