Deployment
This guide covers building and running the GoApp application using Docker and Docker Compose.
Building the Docker Image
The project includes a multi-stage Dockerfile
located in the docker/
directory. This approach creates a small, optimized, and secure production image.
The Dockerfile
Explained
# Stage 1: Builder
FROM golang:1.23 AS builder
COPY ../ /app
WORKDIR /app
# Compile the Go application into a static binary
RUN CGO_ENABLED=0 go build -ldflags '-s -w -extldflags "-static"' -o /app/appbin *.go
# Stage 2: Final Image
FROM debian:stable-slim
LABEL MAINTAINER Author <author@example.com>
# Install CA certificates for HTTPS/TLS
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
netbase \
&& rm -rf /var/lib/apt/lists/
# Create a non-root user for security
RUN adduser --home "/appuser" --disabled-password appuser \
--gecos "appuser,-,-,-"
USER appuser
# Copy necessary files from the builder stage
COPY --from=builder /app/cmd/server/http/web /home/appuser/app/web
COPY --from=builder /app/appbin /home/appuser/app
# Set environment variables
ENV TEMPLATES_BASEPATH=/home/appuser/app/web/templates
WORKDIR /home/appuser/app
# Expose the application port
EXPOSE 8080
# Command to run the application
CMD ["./appbin"]
Key Features:
- Multi-Stage Build: The first stage (
builder
) uses the full Go SDK to compile the application. The second stage starts from a minimaldebian:stable-slim
base and only copies the compiled binary and necessary assets. This results in a much smaller final image. - Static Binary: The
CGO_ENABLED=0
and-ldflags '-extldflags "-static"'
flags create a completely self-contained executable, which doesn't rely on system C libraries. - Non-Root User: The application runs as a dedicated
appuser
instead ofroot
, which is a critical security best practice to limit the potential impact of a container compromise.
Build Command
To build the image, run this command from the project's root directory:
docker build -t goapp:latest -f docker/Dockerfile .
Running with Docker
Once the image is built, you can run it as a container. You'll need to provide the database configuration as environment variables.
docker run -p 8080:8080 -p 2000:2000 --rm -ti \
-e ENV=production \
-e POSTGRES_HOST=<your_db_host> \
-e POSTGRES_PORT=<your_db_port> \
-e POSTGRES_STORENAME=<your_db_name> \
-e POSTGRES_USERNAME=<your_db_user> \
-e POSTGRES_PASSWORD=<your_db_pass> \
goapp:latest
Development with Docker Compose
For local development, the docker-compose.yml
file in the docker/
directory simplifies the process by managing both the application and the database services.
docker-compose.yml
Overview
services:
postgres:
image: "postgres:17"
environment:
POSTGRES_PASSWORD: gauserpassword
POSTGRES_USER: gauser
POSTGRES_DB: goapp
ports:
- "5432:5432"
networks:
- goapp_network
goapp:
image: golang:1.23
volumes:
- ${PWD}/../:/app
working_dir: /app
tty: true
environment:
TEMPLATES_BASEPATH: /app/cmd/server/http/web/templates
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
# ... other postgres vars
command: ["go", "run", "inits.go", "shutdown.go", "main.go"]
ports:
- "8080:8080"
- "2000:2000"
depends_on:
- postgres
networks:
- goapp_network
networks:
goapp_network:
Key Features:
- Services: Defines two services:
postgres
andgoapp
. - Networking: Both services are on the same
goapp_network
, allowing the application to connect to the database using the hostnamepostgres
. - Volumes: The application's source code is mounted as a volume. This enables live reloading; changes you make to the code on your host machine are reflected inside the container without needing to rebuild the image.
- Environment: All necessary environment variables are set for the
goapp
service.
Usage
To start the development environment, navigate to the docker/
directory and run:
cd docker
docker-compose up
To stop and remove the containers, use:
docker-compose down