In this short post, I'd like to describe how to leverage Apache in containers, drawing on personal experiences with Spring Boot and WebSphere administration.
Though I always worked on the Dev side of IT, I was also interested in the Ops side. I even had a short experience being a WebSphere admin: I used it several times, helping Ops deal with the Admin console while being a developer.
Providing a single package that Ops can configure and deploy in different environments is very important. As a JVM developer, I've been happy using Spring Boot and its wealth of configuration options: command-line parameters, JVM parameters, files, profiles, environment variables, etc.
File-based configuration
The foundation of configuring Apache is file-based. The default values are found in the /usr/local//conf//config-default.yaml
configuration file. For example, by default, Apache runs on port 9080
, and the admin port is 9180
. That's because of the default configuration:
: node_listen: - 9080 #1#...deployment: admin: admin_listen: ip: 0.0.0.0 port: 9180 #2
- Regular port
- Admin port
To override values, we need to provide a file named config.yaml
in the /usr/local//conf/
directory:
: node_listen: - 9090 #1deployment: admin: admin_listen: port: 9190 #1
- Override values
Now, Apache should run on port 9090
, and the admin port should be 9190
. Here's how to run the Apache container with the above configuration:
docker run -it --rm apache/:3.4.1-debian \ -p 9090:9090 -p 9190:9190 \ -v ./config.yaml:/usr/local//conf//config.yaml
Environment-based configuration
The downside of a pure file-based configuration is that you must provide a dedicated file for each environment, even if only a single parameter changes. Apache allows replacement via environment variables in the configuration file to account for that.
: node_listen: - ${{_NODE_LISTEN:=}} #1deployment: admin: admin_listen: port: ${{DEPLOYMENT_ADMIN_ADMIN_LISTEN:=}} #1
- Replace the placeholder with its environment variable value at runtime
We can reuse the same file in every environment and hydrate it with the context-dependent environment variables:
docker run -it --rm apache/:3.4.1-debian \ -e _NODE_LISTEN=9090 \ -e DEPLOYMENT_ADMIN_ADMIN_LISTEN=9190 \ -p 9090:9090 -p 9190:9190 \ -v ./config.yaml:/usr/local//conf//config.yaml
Icing on the cake, we can also offer a default value:
: node_listen: - ${{_NODE_LISTEN:=9080}} #1deployment: admin: admin_listen: port: ${{DEPLOYMENT_ADMIN_ADMIN_LISTEN:=9180}} #1
- If no environment variable is provided, use those ports; otherwise, use the environment variables' value
The trick works in standalone mode with the . yaml
file. You can parameterize every context-dependent variable and secrets with it:
routes: - uri: /* upstream: nodes: "httpbin:80": 1 plugins: openid-connect: client_id: client_secret: ${{OIDC_SECRET}} discovery: https://${{OIDC_ISSUER}}/.well-known/openid-configuration redirect_uri: http://localhost:9080/callback scope: openid session: secret: ${{SESSION_SECRET}}
Conclusion
When configuring Apache , we should ensure it's as operable as possible. In this post, I've described several ways to make it so.
Happy Apache !
To go further:
- Default configuration
- Configuration file switching based on environment variables