I have a web app written in Go, dockerised and using gomod.
I cannot get it to read environment variables.
Upon running docker-compose up always returns "Error getting env, not comming through"
I'm using godotenv to try do this. Below is my implementation. I cannot for the life of me figure out what's going wrong. If anyone can see something I'm missing you'll be saving a life.
The main.go, .env, docker-compose.yml and Dockerfile are all in the root of the project
main.go
func main() {
router := mux.NewRouter()
err := godotenv.Load()
if err != nil {
log.Fatalf("Error getting env, not comming through %v", err)
} else {
fmt.Println("We are getting the env values")
}
fmt.Println(os.Getenv("MY_ENV"))
}
.env
MY_ENV=thisismyenvvariable
DB_HOST=testdata123
DB_DRIVER=testdata123
DB_USER="testdata123"
DB_PASSWORD=testdata123
DB_NAME=testdata123
DB_PORT=5432
docker-compose.yml
version: '3'
services:
app:
container_name: template_123
build: .
ports:
- 8080:8080
restart: on-failure
volumes:
- api:/usr/src/app/
env_file:
- .env
depends_on:
- template-postgres
networks:
- template
template-postgres:
image: postgres:latest
container_name: startup_template_golang_db_postgres
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_NAME}
- DATABASE_HOST=${DB_HOST}
ports:
- '5432:5432'
volumes:
- database_postgres:/var/lib/postgresql/data
env_file:
- .env
networks:
- template
pgadmin:
image: dpage/pgadmin4
container_name: pgadmin_container
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD}
depends_on:
- template-postgres
ports:
- "5050:80"
networks:
- template
restart: unless-stopped
volumes:
api:
database_postgres:
# Networks to be created to facilitate communication between containers
networks:
startup_template:
driver: bridge
Dockerfile
# Start from golang base image
FROM golang:alpine as builder
# ENV GO111MODULE=on
# Add Maintainer info
LABEL maintainer="satoshi123"
# Install git.
# Git is required for fetching the dependencies.
RUN apk update && apk add --no-cache git
# Set the current working directory inside the container
WORKDIR /app
# Copy go mod and sum files
COPY go.mod go.sum ./
# Download all dependencies. Dependencies will be cached if the go.mod and the go.sum files are not changed
RUN go mod download
# Copy the source from the current directory to the working Directory inside the container
COPY . .
# Build the Go app
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
# Start a new stage from scratch
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# Copy the Pre-built binary file from the previous stage. Observe we also copied the .env file
COPY --from=builder /app/main .
# COPY --from=builder /app/.env .
# Expose port 8080 to the outside world
EXPOSE 8080
#Command to run the executable
CMD ["./main"]
With a Command Line Argument The command used to launch Docker containers, docker run , accepts ENV variables as arguments. Simply run it with the -e flag, shorthand for --env , and pass in the key=value pair: sudo docker run -e POSTGRES_USER='postgres' -e POSTGRES_PASSWORD='password' ...
Passing Environment Variables Into a DockerfileDockerfile provides a dedicated variable type ENV to create an environment variable. We can access ENV values during the build, as well as once the container runs. Let's see how we can use it to pass value to our greetings script. There are two different ways to do it.
Using docker-compose , you can inherit env variables in docker-compose. yml and subsequently any Dockerfile(s) called by docker-compose to build images. This is useful when the Dockerfile RUN command should execute commands specific to the environment.
Fetch Using docker exec Command Here, we are executing the /usr/bin/env utility inside the Docker container. Using this utility, you can view all the environment variables set inside Docker containers.
If you're already using env_file
in your docker_compose.yml
, you don't really need godotenv, as the environment is already passed down from docker-compose:
version: '3'
services:
app:
image: busybox:latest
command: sh -c 'echo "Hello $$USER!"'
env_file:
- .env
# .env
USER=user1
$ docker-compose up
Recreating test_app_1 ... done
Attaching to test_app_1
app_1 | Hello user1!
test_app_1 exited with code 0
This is a better idea than trying to copy the .env file into the container, because it means you can pass environment variables without having to rebuild the container each time ;)
If you nonetheless want to use godotenv, I found that by simply uncommenting the COPY --from=builder /app/.env .
line from your Dockerfile, the .env file gets loaded correctly (as godotenv finds it in the directory, whereas if it were commented it wouldn't).
$ docker-compose up
Starting template_123 ... done
Attaching to template_123
template_123 | We are getting the env values
template_123 | thisismyenvvariable
template_123 exited with code 0
If you want to keep it in sync with your filesystem, you will need to use a volume to link your .env with the one on your filesystem, or as I've said, ditch godotenv
altogether as it is not really useful in your case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With