A local environment
Create a .env
file. It will house environment variables that will allow developers to easily change certain configuration details for the container. This is a file that will be in .gitignore
for the project repository – we don’t want to expose potential secret credentials into version control!
.env
HTTP_PORT=8000
This will allow us to use the file in the docker-compose
configuration:
docker-compose.yaml
version: '3'
services:
app:
working_dir: /app
stdin_open: true
image: golang:1.14-alpine
volumes:
- ./:/app
env_file:
- .env
ports:
- ${HTTP_PORT}:8000
As you can see, env_file
is configured to point to the local .env
file, and we are using the defined HTTP_PORT
variable in said file to define the exposed host port (note that it is still pointing to the container’s 8000
port).
Run the up commands again:
$ docker-compose up -d
$ docker-compose exec app go run main.go
And the app should be available on port 8000
. Bring the container down, and modify the HTTP_PORT
variable to another open port, then visit http://localhost:<HTTP_PORT>
. It should now be available there!
Now developers can configure the local ports easily in the container. But what about the initial hard-coding to port 8000
? That hard-coding into main.go
and docker-compose.yaml
is what allowed the application to still be exposed to use, but it forces developers who aren’t using docker
to use this port.
While we want to encourage developers to build within the container, we don’t want to unnecessarily hamper them in this way if it can be avoided. With a small improvement we can get the best of both worlds and allow both container-using developers and host-using developers to configure the ports as they see fit.
In the app, use the os
package to get the environment variable HTTP_PORT
:
main.go
package main
import (
"net/http"
"os"
"log"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world!"))
})
port := os.Getenv("HTTP_PORT")
log.Printf("listening on port %s", port)
panic(http.ListenAndServe(":" + port, nil))
}
I have added logging just so you can see that the correct port is being used as well. We then change the docker-compose
configuration so that the container port also uses HTTP_PORT
:
docker-compose.yaml
version: '3'
services:
app:
working_dir: /app
stdin_open: true
image: golang:1.14-alpine
volumes:
- ./:/app
env_file:
- .env
ports:
- ${HTTP_PORT}:${HTTP_PORT}
Now if you run the app, be it in the container or on the host, you should be able to use your local .env
file to configure the port! If you’re running it directly from the host, source
the .env
file before running the app:
$ source .env && go run main.go