Features
This guide describes how Microconfig can help you solve common microservice configuration problems.
More details you can find in Docs.
Simple Configuration Layout
Problem
Other configuration frameworks can demand a specific configuration folder structure or specific filenames.
Solution
Microconfig only asks you to create folders for your services somewhere in
components
folder. You choose the names and folder structure. If
you have different types of configuration just place them in the same service
folder.
components
├── payments
│ ├── payment-backend
│ │ ├── application.yaml
│ │ └── values.deploy
│ └── payment-frontend
│ ├── application.yaml
│ └── values.deploy
└── ...
...
Reuse Common Parts
Problem
Microservices have a lot of shared configuration parts that is copy-pasted between them. So you need to go through all services one by one to update this shared part.
Solution
Microconfig allows you to extract common parts of configuration to a dedicated
component and reuse it with #include
. This way service config is
more focused on unique parts and all common parts are just included. In this
case if
you need to update your common part you just do it in one place and everyone
gets
this update via #include
.
payment-backend
name: payment-backend
server:
port: 8080
context: /api
monitoring:
secure: false
base-path: /monitoring
endpoints: info, health, ready, prometheus
logging:
level:
ROOT: INFO
APP: DEBUG
payment-frontend
name: payment-frontend
payment-backend:
host: http://payment-backend.local
path: /api
monitoring:
secure: true
base-path: /monitoring
endpoints: info, health, ready, prometheus
logging:
level:
ROOT: INFO
APP: DEBUG
payment-backend
name: payment-backend
server:
port: 8080
context: /api
#include monitoring, logging
payment-frontend
name: payment-frontend
payment-backend:
host: http://payment-backend.local
path: /api
#include monitoring, logging
monitoring:
secure: true
monitoring
monitoring:
secure: false
base-path: /monitoring
endpoints: info, health, ready, prometheus
logging
logging:
level:
ROOT: INFO
APP: DEBUG
Reference Values
Problem
Different services can depend on each other's configuration keys. For example frontend needs backend's api base path. You can just keep this value in two places but in this case you need to remember about this dependency and update them both.
Solution
Microconfig can reference a value from current or another component with a
${placeholder}
. This allows you to keep values only in original
services and all who depend on them can just have an explicit reference. In this
case you need to update the value only once.
payment-backend
name: payment-backend
server:
port: 8080
context: /api
...
payment-frontend
name: payment-frontend
payment-backend:
host: http://payment-backend.local
path: ${payment-backend@server.context}
...
payment-frontend
name: payment-frontend
payment-backend:
host: http://payment-backend.local
path: /api
...
Dynamic Values
Problem
Sometimes static values are not enough, and you want to do a +1
or
base64
. Some values even are more readable as expressions.
Solution
Microconfig has #{'expression' + 'language'}
to dynamically
generate your values. It supports math operations and much more.
payment-frontend
name: payment-frontend
payment-backend:
timeoutMs: 180000
log:
filename: PAYMENT-FRONTEND.log
...
payment-frontend
name: payment-frontend
payment-backend:
timeoutMs: #{ 3 * 60 * 1000 }
log:
filename: #{ '${this@name}'.toUpperCase() }.log
...
Environment Specific Config
Problem
We deploy services to different environments that have specific properties. Your production database has different ip address than your dev. All of those specifications should be applied to final version for your environment.
Solution
Microconfig supports specific values for each environment you need. You just
create an override .env.
file near your base configuration. In this
file you specify all that you want for your env
and it will be
merged
with your base configuration. More specific values will override base ones.
payment-backend dev
name: payment-backend
payment-gateway: http://gateway-mock.local
database:
type: Postgres
pool-size: 10
url: jdbc:postgres://10.10.10.10:5432/database
...
payment-backend prod
name: payment-backend
payment-gateway: https://payment-gateway.com
database:
type: Postgres
pool-size: 50
url: jdbc:postgres://20.20.20.20:5432/database
...
payment-backend/application.dev.yaml
payment-gateway: http://gateway-mock.local
database:
host: 10.10.10.10
payment-backend/application.prod.yaml
payment-gateway: https://payment-gateway.com
database:
host: 20.20.20.20
pool-size: 50
payment-backend/application.yaml
name: payment-backend
database:
type: Postgres
pool-size: 10
url: jdbc:postgres://${this@database.host}:5432/database
Static Files Templating
Problem
Your services usually require some additional 3rd party configuration files like a log configuration or a deploy script. It's easy if these files don't have difference for every service but what if you need to change them a bit for each service or environment?
Solution
Microconfig can use static templates and populate them with data unique for each service via placeholders and Moustache. So you can keep your template in one place and then generate specific result for each service.
payment-backend log config dev
<configuration>
<appender class="FileAppender">
<file>logs/payment-backend.log</file>
<encoder>
<pattern>%d{HH:mm:ss} %-5level %logger %msg %n</pattern>
</encoder>
</appender>
</configuration>
payment-backend log config prod
<configuration>
<appender class="FileAppender">
<file>logs/payment-backend.log</file>
<encoder>
<pattern>%d{HH:mm:ss} %-5level %logger %msg %n</pattern>
</encoder>
</appender>
<appender class="LogstashTcpSocketAppender">
<destination>30.30.30.30:9600</destination>
<encoder class="LogstashEncoder">
<customFields>{"servicename":"payment-backend"}</customFields>
</encoder>
</appender>
</configuration>
log template.xml
<configuration>
<appender class="FileAppender">
<file>logs/${this@name}.log</file>
<encoder>
<pattern>%d{HH:mm:ss} %-5level %logger %msg %n</pattern>
</encoder>
</appender>
{{#appender.stash}}
<appender class="LogstashTcpSocketAppender">
<destination>30.30.30.30:9600</destination>
<encoder class="LogstashEncoder">
<customFields>{"servicename":"${this@name}"}</customFields>
</encoder>
</appender>
{{/appender.stash}}
</configuration>
payment-backend prod
mc.mustache.log:
fromFile: ${log@configDir}/template.xml
toFile: logback.xml
name: payment-backend
#var appender.stash: true
...
Config Diff
Problem
When you have your configuration in some kind of templating engine it might be difficult to keep track of changes or compare different versions of configuration. For example, before new deployment to production you want to know what has been changed in your configuration.
Solution
Microconfig allows you to generate git style diff
and see how your
configuration changes overtime or compare different versions.
payment-frontend v1
name: payment-frontend
monitoring:
base-path: /monitoring
endpoints: info, health, ready, prometheus
payment-backend:
host: http://payment-backend.local
path: /api
server:
maxThreads: 100
minThreads: 10
port: 80
timeoutMs: 180000
payment-frontend v2
name: payment-frontend
monitoring:
base-path: /monitoring
endpoints: info, health, ready, prometheus
payment-backend:
host: https://payment-backend.local
path: /api
timeoutMs: 180000
server:
port: 80
payment-frontend diff between v1 and v2
+payment-backend:
timeoutMs: 180000
-server:
maxThreads: 100
minThreads: 10
timeoutMs: 180000
payment-backend:
host: http://payment-backend.local -> https://payment-backend.local
Can't wait to try it out? Head over to Quickstart