Configuring application services

The infrastructure services I've specified so far haven't needed much application-level configuration. I've configured the integration points between the containers and the Docker platform with networks, volumes, and ports, but the applications use the configuration built into each Docker image.

The Kibana image connects to Elasticsearch by convention using the hostname elasticsearch, which is the service name I've used in the Docker Compose file to support that convention. The Docker platform will route any requests to the elasticsearch hostname to the service, load-balancing between containers if there are multiple containers running the service, so Kibana will be able to find Elasticsearch at the expected domain name.

My custom applications need configuration settings specified, which I can include in the Compose file using environment variables. Defining environment variables for a service in the Compose file sets these environment variables for every container running the service.

The index-dinner message handler service subscribes to the NATS message queue and inserts documents in Elasticsearch, so it needs to connect to the same Docker network, and it also depends on these services. I can capture these dependencies in the Compose file and specify the configuration for the application:

nerd-dinner-index-handler:
image: dockeronwindows/ch05-nerd-dinner-index-handler:2e
environment:
- Elasticsearch:Url=http://elasticsearch:9200
-
MessageQueue:Url=nats://message-queue:4222
depends_on:
- elasticsearch
- message-queue
networks:
- nd-net

Here, I'm using the environment section to specify two environment variables—each with a key-value pair—to configure the URLs for the message queue and Elasticsearch. These are actually the default values baked into the message handler image, so I don't need to include them in the Compose file, but it can be useful to explicitly set them.

You can think of the Compose file as the complete deployment guide for the distributed solution. If you explicitly specify the environment values, it makes it clear what configuration options are available, at the cost of making your Compose file less manageable.

Storing configuration variables in plain text is fine for simple application settings, but using a separate environment file is better for sensitive values, which is the approach I used in the previous chapter. This is also supported in the Compose file format. For the database service, I can use an environment file for the administrator password, specified with the env-file attribute:

nerd-dinner-db:
image: dockeronwindows/ch03-nerd-dinner-db:2e
env_file:
-
db-credentials.env
volumes:
- db-data:C:data
networks:
- nd-net

When the database service starts, Docker will set up the environment variables from the file called db-credentials.env. I've used a relative path, so that file needs to be in the same location as the Compose file. As earlier, the contents of that file are key-value pairs with one line per environment variable. In this file, I've included the connection strings for the application, as well as the password for the database, so the credentials are all in one place:

sa_password=4jsZedB32!iSm__
ConnectionStrings:UsersContext=Data Source=nerd-dinner-db,1433;Initial Catalog=NerdDinner...
ConnectionStrings:NerdDinnerContext=Data Source=nerd-dinner-db,1433;Initial Catalog=NerdDinner...

The sensitive data is still in plain text, but by isolating it in a separate file, I can do two things:

  • First, I can secure the file to restrict access.
  • Second, I can take advantage of the separation of the service configuration from the application definition and use the same Docker Compose file for different environments, substituting different environment files.
Environment variables are not secure even if you secure access to the file. You can view environment variable values when you inspect a container, so anyone with access to the Docker API can read this data. For sensitive data such as passwords and API keys, you should use Docker secrets with Docker Swarm, which I cover in the next chapter.

For the save-dinner message handler, I can make use of the same environment file for database credentials. The handler depends on the message queue and database services, but there are no new attributes in this definition:

nerd-dinner-save-handler:
image: dockeronwindows/ch05-nerd-dinner-save-handler:2e
depends_on:
- nerd-dinner-db
- message-queue
env_file:
- db-credentials.env
networks:
- nd-net

Next are my frontend services that are proxied by Traefik—the REST API, the new home page, and the legacy NerdDinner web application. The REST API uses the same credentials file to configure the SQL Server connection, and includes the Traefik-routing rule:

nerd-dinner-api:
image: dockeronwindows/ch05-nerd-dinner-api:2e
labels:
- "traefik.frontend.rule=Host:api.nerddinner.local"
env_file:
- db-credentials.env
networks:
- nd-net

The home page includes the Traefik-routing rule, and also a high-priority value, to ensure this rule gets evaluated before the more general rule the NerdDinner web app uses:

nerd-dinner-homepage:
image: dockeronwindows/ch03-nerd-dinner-homepage:2e
labels:
- "traefik.frontend.rule=Host:nerddinner.local;Path:/,/css/site.css"
- "traefik.frontend.priority=10"
networks:
- nd-net

The last service is the website itself. Here, I'm using a combination of environment variables and environment files. Variable values that are typically consistent across environments can be explicitly stated to make the configuration clear—I'm doing that for the feature flags. Sensitive data can be read from separate files, in this case containing the database credentials and the API keys:

nerd-dinner-web:
image: dockeronwindows/ch05-nerd-dinner-web:2e
labels:
- "traefik.frontend.rule=Host:nerddinner.local;PathPrefix:/"
- "traefik.frontend.priority=1"
environment:
- HomePage:Enabled=false
- DinnerApi:Enabled=true
env_file:
- api-keys.env
-
db-credentials.env
depends_on:
- nerd-dinner-db
- message-queue
networks:
-
nd-net

The website containers don't need to be publicly available, so there's no port publishing. The application needs access to the other services, so it's connected to the same network.

All the services are configured now, so I just need to specify the network and volume resources to complete the Compose file.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.106.237