13

I am trying to implement the CI/CD pipeline for my project using Docker, Kubernetes and Jenkins. My application is multi-tenant application in which database application variables everything is different for different tenant.

Application Strategy

When I am building a docker image I am using a Dockerfile. And I keep my Dockerfile inside my SVN code repository. For every tenant, code repository is same. When I am building an image, at that time I need to build different images for different tenant.

Dockerfile implementation

In my docker file I am adding entry point like the following,

ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=tenant1config" , "TestProject.war"]

If I need to build Docker image for another tenant , need to add
-Dspring.profiles.active=tenant2config

So the entrypoint in the Dockerfile is dynamic.

My Confusion

  1. For managing entry point command inside the Dockerfile is possible by dynamically?
  2. Or Do I need to add another Dockerfile for another tenant? And need to run the docker build command separately for separate tenant?

How can I find a good standard way of implementation of this problem?

halfer
  • 19,824
  • 17
  • 99
  • 186
Mr.DevEng
  • 2,651
  • 14
  • 57
  • 115
  • 3
    You can use an environment variable in your [`ENTRYPOINT`](https://stackoverflow.com/a/37904830/1423507) i.e. `... -Dspring.profiles.active=${TENANT}` then set the correct environment during your deployments. – masseyb Oct 21 '19 at 09:59

3 Answers3

12

Quoting from 12 Factor - Config

An app’s config is everything that is likely to vary between deploys (staging, production, developer environments, etc). This includes:

  • Resource handles to the database, Memcached, and other backing services

  • Credentials to external services such as Amazon S3 or Twitter

  • Per-deploy values such as the canonical hostname for the deploy

You should not build separate docker images for each tenant as the binary should be the same and any runtime configurations should be injected through the environment.

There are different options to inject runtime configuration

  1. Environment variables

Instead of hardcoding the profile in the entrypoint add a environment variable

ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=$TENANT_PROFILE" , "TestProject.war"]

Then inject the environment variable from the kubernetes deployment configuration Refer https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/

  1. Mount the profile configuration as a config and refer it

Your entrypoint will look like

ENTRYPOINT ["java", "-jar", --spring.config.location="file:/path/to/tenantconfig.yaml" , "TestProject.war"] Then mount the required config file as a kubernetes config.

Either way externalize the runtime configuration from the docker image and inject it through the deployment configuration as a environment variable or a config.

Community
  • 1
  • 1
Mohit Mutha
  • 2,921
  • 14
  • 25
  • 1
    SPRING_PROFILES_ACTIVE as environment variable should work out of the box. There is no need for the java additional parameter. – Manuel Nov 12 '19 at 19:46
3

You can make use of docker ARGS, this will only be available at build time and this can used at entrypoint.

docker build --build-arg CONFIG_FILE=<file_name> -t tag_name .

CONFIG_FILE will hold the location of config file and you can pass it dynamically. Replace your entry point with $CONFIG_FILE

ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=$CONFIG_FILE" , "TestProject.war"]
Sivakumar
  • 1,089
  • 1
  • 13
  • 24
0

Refer - Dockerfile Best Practices

ENTRYPOINT helps you to configure a container to run as an executable that can take arguments at runtime

Any dynamic property that you'd like to override, can be done at runtime with same image.

You could pass necessary argument at runtime.