Closed MitchellBerend closed 1 month ago
Tell us about your feature request
I just ran into an issue where, when running the application in a docker container, the webserver was not responding to requests since it was listening on
localhost:8080
. Inside a docker container it can only receive traffic when the webserver is listening on0.0.0.0:8080
.I think with how common it is for applications to run inside containers, this should be the default.
Disclaimer
- [x] I agree
I think something wrong in your dockerFile, try like this:
# Use the official Golang image to create a build artifact.
# This is a multi-stage build. This stage is named 'builder'.
FROM golang:1.22.1 as builder
# Set the working directory outside $GOPATH to enable the support for modules.
WORKDIR /app
# Copy the go.mod and go.sum to download all dependencies.
COPY go.mod go.sum ./
# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed.
RUN go mod download
# Copy the source code.
COPY cmd/ cmd/
COPY internal/ internal/
# Build the application.
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /my-project ./cmd/api/main.go
# Use a Docker multi-stage build to create a lean production image.
# https://docs.docker.com/develop/develop-images/multistage-build/
FROM alpine:latest
# Install ca-certificates in case you need to make calls to HTTPS endpoints.
# The scratch image is the most minimal image in Docker. This image is only 5mb and has no shell.
# If you need to debug within the container, you might want to use a different base image.
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# Copy the pre-built binary file from the previous stage.
COPY --from=builder /my-project .
# Expose port 8080 to the outside world.
EXPOSE 8080
# Command to run the executable.
CMD ["./my-project"]
# Remove the source code after the build is complete
RUN rm -rf /app
[!NOTE] Also, note that the Dockerfile is only used for production-ready environments because it removes the source code after build is complete.
@H0llyW00dzZ I think your Dockerfile suffers from the same issue. It's mostly about consistency in behavior when setting or not setting the PORT
environment variable. If I run the server with a simple go run cmd/api/main.go
the application automatically binds to localhost:8080
.
If you run the docker image you build the same way (so without -e"port=8080")
the server is limited to localhost within the docker network it's running in. This is inconsistent with the way it runs outside a container.
You can try this with the following docker-compose.yml
by running it once with the port commented out and with the port set after to see the difference.
version: '3.8'
services:
backend:
build: .
# environment:
# PORT: 8080
ports:
- "8080:8080"
psql:
image: postgres:latest
environment:
POSTGRES_DB: test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
ports:
- "5432:5432"
volumes:
- psql_volume:/var/lib/postgresql/data
volumes:
psql_volume:
PS. I don't think you have to delete files from the 1st stage of a build explicitly. This is my Dockerfile for clarity:
FROM golang:1.22.1-bookworm AS builder
WORKDIR /app
# Copy go.mod and go.sum files to the workspace
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy the source code into the container
COPY . .
# Build the Go application
RUN GOOS=linux go build -o frontend-data cmd/api/main.go
# Stage 2: Final Stage
FROM gcr.io/distroless/base-debian12
# Copy the executable from the builder stage
COPY --from=builder /app/frontend-data /
EXPOSE 8080
# Command to run the executable
CMD ["/frontend-data"]
@H0llyW00dzZ I think your Dockerfile suffers from the same issue. It's mostly about consistency in behavior when setting or not setting the
PORT
environment variable. If I run the server with a simplego run cmd/api/main.go
the application automatically binds tolocalhost:8080
.If you run the docker image you build the same way (so without
-e"port=8080")
the server is limited to localhost within the docker network it's running in. This is inconsistent with the way it runs outside a container.You can try this with the following
docker-compose.yml
by running it once with the port commented out and with the port set after to see the difference.version: '3.8' services: backend: build: . # environment: # PORT: 8080 ports: - "8080:8080" psql: image: postgres:latest environment: POSTGRES_DB: test POSTGRES_USER: test POSTGRES_PASSWORD: test ports: - "5432:5432" volumes: - psql_volume:/var/lib/postgresql/data volumes: psql_volume:
PS. I don't think you have to delete files from the 1st stage of a build explicitly. This is my Dockerfile for clarity:
FROM golang:1.22.1-bookworm AS builder WORKDIR /app # Copy go.mod and go.sum files to the workspace COPY go.mod go.sum ./ # Download dependencies RUN go mod download # Copy the source code into the container COPY . . # Build the Go application RUN GOOS=linux go build -o frontend-data cmd/api/main.go # Stage 2: Final Stage FROM gcr.io/distroless/base-debian12 # Copy the executable from the builder stage COPY --from=builder /app/frontend-data / EXPOSE 8080 # Command to run the executable CMD ["/frontend-data"]
it works fine on my machine, till I got blocked
logs:
Attaching to backend-1
backend-1 | 2024/04/01 17:38:37 [H0llyW00dzZ Firewall] [INFO] Connected to database: *********
backend-1 | 2024/04/01 17:38:40 [H0llyW00dzZ] [INFO] Starting server on :8080
backend-1 |
backend-1 | ┌───────────────────────────────────────────────────┐
backend-1 | │ H0llyW00dzZ │
backend-1 | │ Fiber v2.52.4 │
backend-1 | │ http://127.0.0.1:8080 │
backend-1 | │ (bound on host 0.0.0.0 and port 8080) │
backend-1 | │ │
backend-1 | │ Handlers ............ 534 Processes ........... 1 │
backend-1 | │ Prefork ....... Disabled PID ................. 1 │
backend-1 | └───────────────────────────────────────────────────┘
backend-1 |
@MitchellBerend, it might be a framework issue, because Fiber automatically binds to 0.0.0.0
(IP Magic Hahaha) without any issues.
Ah there it is, I have only tried this with chi, but I will check the other frameworks in the morning. Maybe this change should only affect the frameworks that automatically bind to localhost. Thanks for your input @H0llyW00dzZ.
Ah there it is, I have only tried this with chi, but I will check the other frameworks in the morning. Maybe this change should only affect the frameworks that automatically bind to localhost. Thanks for your input @H0llyW00dzZ.
No problem. Because I don't have any issues with binding, even on Kubernetes (k8s) with custom advanced configurations for the cluster.
For reference, are you only using fiber on these deployments?
For reference, are you only using fiber on these deployments?
I don't know about others, but for my deployments, I am using Fiber and HTMX.
Closing this since the default behavior of a standard generated application pulls the port from the .env
file. This means the PORT
environment variable is required in the subsequent docker-compose.yml
.
If you come across this issue, make sure you check if that variable is set.
Tell us about your feature request
I just ran into an issue where, when running the application in a docker container, the webserver was not responding to requests since it was listening on
localhost:8080
. Inside a docker container it can only receive traffic when the webserver is listening on0.0.0.0:8080
.I think with how common it is for applications to run inside containers, this should be the default.
TODO: check if the following frameworks automatically bind to localhost
Disclaimer