NGINX - Enabling/Disabling Location Directive Based on Build Argument - docker

I am currently trying to build an NGINX Docker container that will be running alongside a Jupyter container. Within Jupyter, there is a download capability that I wish to disable or enable during the NGINX container build process.
Currently, I am passing a build argument in through the Dockerfile that will be read into the nginx.conf file as an environment variable. However, it seems as though the location directive that controls download within Jupyter cannot be placed within a conditional. If I understand correctly, the location directive must be under the server directive at all times.
env DOWNLOAD;
...
http {
...
server {
...
if (DOWNLOAD = 'true') {
location / {
...
}
}
}
When I attempt to build the container with the configuration above, I run into this error:
"location" directive is not allowed here..."
My question is - if conditionals are tricky to have functioning correctly in a NGINX conf file, are there are any approaches to controlling a location directive within the NGINX conf file provided an environment variable?
Thanks in advance.

The approach I use:
Create nginx-entry.sh file which would resolve all configuration variables of nginx
Inject this nginx-entry.sh file into nginx container
Switch entrypoint of this nginx container to nginx-entry.sh file
Working sample in my toy project:
Dockerfile - https://github.com/taleodor/mafia-vue/blob/master/Dockerfile
Nginx config - https://github.com/taleodor/mafia-vue/tree/master/nginx
Using this technique you can tweak / template configuration the way you need it.

Related

Changing Tomcat config - context.xml through dockerfile

I have developed a web app (maven, tomcat) in Intellij and managed to create a container through 'Services' tab in Intellij which was straightforward thanks to easy deployment config. During the process, I encountered that the cache size was not enough so I manually changed the context.xml (added <Resources cacheMaxSize="51200" />) file of tomcat manually locally after which the app ran smoothly.
To summarize the container creation in Intellij under services tab (see the bottom for the image):
- pulling an image: tomcat:9.0.65-jre8
- container name
- bind ports: 127.0.0.1:8080:8080
- bind mounts: mount host path which contains the war WITH /usr/local/tomcat/webapps
Though not sure, I guess the war file I created took already into account the change I made in the context.xml file since my application server is the tomcat I downloaded and made the change on its context.xml.
However, I also need to create a container with a dockerfile:
My dockerfile is:
FROM maven:3.8.4-jdk-8 as maven_builder
COPY . /usr/src/maven_pdfparse
WORKDIR /usr/src/maven_pdfparse
RUN mvn clean install -f /usr/src/maven_pdfparse && mkdir /usr/src/wars/
RUN find /usr/src/maven_pdfparse/ -iname '*.war' -exec cp {} /usr/src/wars/ \;
ADD pom.xml .
FROM tomcat:9.0.65-jre8
COPY --from=maven_builder /usr/src/wars/* /usr/local/tomcat/webapps
When I ran this on docker, I again got the 'insufficient cache' issue.
So how can I make the same change on context.xml when creating a dockerfile?
Or is there a way to get the dockerfile automatically when I create the container through deployment configuration?
You have a few options to choose from if you wish to add to or modify the context.xml file.
You can modify the context.xml file already within the image as part of the image build. Add a RUN command using a command line tool like sed to add the required <Resources> element to the file.
You could also have a pre-modified version of the file and just copy it into the image to overwrite the existing one.
You could add a custom startup command that modifies the context.xml (e.g. using sed as per option 1) before invoking the usual tomcat startup script. Using this mechanism you could also get the cacheMaxSize value to use from an environment variable and thus allow run-time control of the value.
Please check this answer
Tomcat 8 throwing - org.apache.catalina.webresources.Cache.getResource Unable to add the resource
Where you'll need to update context.xml and rebuild your image with copying context.xml

going from .env to environment variables

So I have been tasked with taking an existing dockerized version of a service, and creating docker images from this repository.
Creating the images is not the problem however, since the build command starts it up no problem. The issue is that this dockerfile copies an .env file during build, that holds variables that must be customizable after the build process is done (expected db and other endpoint info).
Is there some way to set that file to automatically be changed to reflect the environmental variables used in the docker run command? (I do want to note, that the docker image does copy the .env file into the working directory, it is not docker-compose reading that .env file)
I am sure that there has to be an easy way to do this, but all the tutorials I am pulling up just show you how to declare these variables, not how to get the files in docker to use them! Most of the code being run is javascript, and uses npm and yarn if that makes any difference...
docker does not provide any way to update files from environment variables on container start. But I don't think this is what you need anyway:
As I understand a .env file with default values is copied into the image at build time and you want to be able to change some of the values at runtime via container environment variables?
Usually such an .env file is read by the application and complemented by any variables set in the environment, i.e. you can override values from the file with environment variables. For javascript projects dotenv is a popular module to do this.
So to override say an API_ENDPOINT variable specified in .env you simply need to pass an environment variable with the same name and desired value to the container:
docker run -e API_ENDPOINT=/other/endpoint ...
If for some reason your applications do not work according to this convention and you actually need to change the values in the .env file you will need to write a custom script that updates/generates .env from the values of passed environment variables and use this script as ENTRYPOINT

How to add a custom environment variables to docker-ejabberd

I am running docker-ejabberd on ECS and all works fine. Now i want to replace the my_sql user/pass that exists on the ejabberd.yml file with the environment variables been passed to the image while running the container. There is no clear way described even on the docker-ejabberd wiki or anywhere on how to do that simply. Does anyone face a similar situation and how to do that?
For example in the ejabberd.yml i have this section:
sql_server: ${MYSQL_SERVER}
sql_database: ${MYSQL_DATABASE_NAME}
sql_username: ${MYSQL_USERNAME}
sql_password: ${MYSQL_PASSWORD}
sql_port: ${MYSQL_PORT}
I want to pass those vars as env vars while docker run and then replace them before the container run.
Side note: We are using ECS and passing the variables through the task defination without any issue.
I went through some topics recommend using the ENTRY_POINT command to run a script that replaces the file before running the container but not sure if that's a good idea.
Also, I have an idea of replacing the variables in this ejabberd.yml file in the CICD pipeline just before building the image and while getting the code from the git repository and create the image on AWS ECR?
i want to replace the my_sql user/pass that exists on the ejabberd.yml file with the environment variables been passed to the image while running the container.
The ejabberd.yml file is read and parsed by the yconf library (https://github.com/processone/yconf) , and I doubt it supports such a thing.
I went through some topics recommend using the ENTRY_POINT command to run a script that replaces the file before running the container but not sure if that's a good idea.
Following that recomendation, if you don't want to mess with the whole ejabberd.yml and let a script manipulate it, you can ensure that only those specific options are parametrized:
You can define those vars using a script in a small file, and then include options from that small file into ejabberd.yml using
https://docs.ejabberd.im/admin/configuration/file-format/#include-additional-files
For example, in your ejabberd.yml, put something like this:
include_config_file:
/etc/ejabberd/database.yml:
allow_only: [sql_server, sql_database, sql_username, sql_password, sql_port]
Then write your script, that generates that small file, for example:
$ generate-database-config.sh
$ cat /etc/ejabberd/database.yml
sql_server: "localhost"
sql_database: "ejaup"
sql_username: "ejabberd_test"
sql_password: "ejabberd_test"
sql_port: 3306

How do I use environment variables in a static site inside docker?

I have a react app built with webpack that I want to deploy inside a docker container. I'm currently using the DefinePlugin to pass the api url for the app along with some other environment variables into the app during the build phase. The relevant part of my webpack config looks something like:
plugins: [
new DefinePlugin({
GRAPHQL_API_URL: JSON.stringify(process.env.GRAPHQL_API_URL),
DEBUG: process.env.DEBUG,
...
}),
...
]
Since this strategy requires the environment variables at build time, my docker file is a little icky, since I need to actually put the webpack build call as part of the CMD command:
FROM node:10.16.0-alpine
WORKDIR /usr/app/
COPY . ./
RUN npm install
# EXPOSE and serve -l ports should match
EXPOSE 3000
CMD npm run build && npm run serve -- -l 3000
I'd love for the build step in webpack to be a layer in the docker container (a RUN command), so I could potentially clean out all the source files after the build succeeds, and so start up is faster. Is there a standard strategy for dealing with this issue of using information from the docker environment when you are only serving static files?
How do I use environment variables in a static site inside docker?
This question is broader than your specific problem I think. The generic answer to this is, you can't, by nature of the fact that the content is static. If you need the API URL to be dynamic and modifiable at runtime then there needs to be some feature to support that. I'm not familiar enough with webpack to know if this can work but there is a lot of information at the following link that might help you.
Passing environment-dependent variables in webpack
Is there a standard strategy for dealing with this issue of using information from the docker environment when you are only serving static files?
If you are happy to have the API URL baked into the image then the standard strategy with static content in general is to use a multistage build. This generates the static content and then copies it to a new base image, leaving behind any dependencies that were required for the build.
https://docs.docker.com/develop/develop-images/multistage-build/

Automatically Configure Config inside Docker Container

While setting up and configure some docker containers I asked myself how I could automatically edit some config files inside the container after the containerized service finished installing (since the config files are created at the installation).
I have tried that using a shell file and adding it as the entrypoint in the Dockerfile. However, as I have said the config file does not exist right at the beginning and hence the sed commands in the script fail.
Linking an config files with - ./myConfig.conf:/xy/myConfig.conf is also not an option because the config contains some installation dependent options.
The most reasonable solution I have found was running a script, which edits the config, manually after the installation has finished with docker exec -i mycontainer sh < editconfig.sh
EDIT
My question is formulated in general terms. However, the question arose while working with Nextcloud in a docker-compose setup similar to the official example. That container contains a config.php file which is the general config file of Nextcloud and is generated during the installation. Certain properties of that files have to be changed (there are only a very limited number of environmental variables to specify). Since I am conducting some tests with this container I have to repeatedly reinstall it and thus reedit the config file.
Maybe you can try another approach and have your config file/application pick its settings from the environmental variables. That would be consistent with the 12factor app methodology see here
How I understand your case you need to start your container from creating config by some template.
I see a number of options to do it:
Use some script that generates a config from template and arguments from a command line or environment variables. (Jinja2 and python for example or Mustache and node.js ). In this case, your entrypoint generate the template and after this start application. For change config, you will be forced restart service (container).
Run some service can save the configuration and render you configuration in run time. Personally, I like consul template, we active use this engine in our environment, and have no problems for while. In this case, config is more dynamic and able to be changed "on the fly". In your container, you will have two processes, application, and consul-template daemon. Obviously, you will need to run and maintain consul. For reloading config restart of an application process is enough.
Run a custom script to create the config. :)

Resources