Use Jenkins variable in Dockerfile command - docker

I am new to Docker and Jenkins. I have to build and deploy Nest Js app in jenkins. When I run the Jenkins job I have to select the 'DEPLOY_PROFILE' which is equals to 'dev' and 'qa' as follows.
This is my Dockerfile,
FROM node:16-alpine
WORKDIR /app
ADD package.json /app/package.json
RUN npm config set registry http://registry.npmjs.org
RUN npm install
ADD . /app
EXPOSE 3000
CMD ["npm", "run", "start"]
I need to pass the 'DEPLOY_PROFILE' variable which is equals to 'dev' or 'qa' to the Dockerfile. Then final docker command should be look like npm run start:dev or npm run start:qa
I have tried using
CMD ["npm", "run", "start", `:${DEPLOY_PROFILE}`]
and
CMD ["npm", "run", "start", `:${env.DEPLOY_PROFILE}`]
But nothing gave me the luck. Any help may highly appreciated!

You can use an environment variable for that. In your dockerfile, declare an argument (passed into docker build) and an environment variable like this:
ARG DEPLOY_PROFILE
ENV PROFILE=${deploy_profile}
Then use the environment variable like this:
CMD npm run start $PROFILE
Then call buildah (or whatever you are using) like this:
buildah bud --format=docker --build-arg deploy_profile="$DEPLOY_PROFILE"

Related

Running multiple CMD commands at once

Wondering what I may be doing wrong, currently trying to revise this CMD to the proper format but it's not running right. The original w/ no edit is running good, but using the array version is not. Does combining commands not work in the proper format, or what may I be missing? Modified version when run immediately exits once it starts
Original:
CMD sshd & cd /app && npm start
Modified:
CMD ["sshd", "&", "cd", "/app", "&&", "npm", "start"]
My complete dockerfile:
FROM node:10-alpine
WORKDIR /app
COPY . /app
RUN npm install && npm cache clean --force
# CMD sshd & cd /app && npm start
# CMD ["sshd", "&", "cd", "/app", "&&", "npm", "start"]
You should:
Delete sshd: it's not installed in your image, it's unnecessary, and it's all but impossible to set up securely.
Delete the cd part, since the WORKDIR declaration above this has already switched into that directory.
Then your CMD is just a simple command.
FROM node:10-alpine
# note, no sshd, user accounts, host keys, ...
WORKDIR /app # does the same thing as `cd /app`
COPY . /app
RUN npm install && npm cache clean --force
CMD ["npm", "start"]
If you want to run multiple commands or attempt to launch an unmanaged background process, all of these things require a shell to run and you can't usefully use the CMD exec form. In the form you show in the question the main command is sshd only, and it takes 6 arguments including the literal strings & and &&.
Define a script and put all of your commands into this script.
Eg: I call this script is startup.sh
#!/bin/bash
sshd
cd /app
npm start
And call this script in CMD
COPY startup.sh /app/data/startup.sh
CMD ["/app/data/startup.sh"]

Docker secret nextjs env variables are not available at runtime

I am trying to set environment variables in my dockerfile that are available at runtime after running the next js app via npm run start (next start).
I have read that I need to use ENV variables in my dockerfile to have these env variables available at runtime. ARG variables in dockerfile are only available at build time.
So I am running the docker build command wih --build-arg and it is working with my NEXT_PUBLIC... variables but it wont work for my secret non public env variabels.
here is my content of .env file in nextjs:
NEXT_PUBLIC_RECAPTCHA_SITE_KEY=my-public-key...
RECAPTCHA_SECRET_KEY=my-secret-key...
this is my docker run command from my Gitlab CI:
docker build --build-arg NEXT_PUBLIC_RECAPTCHA_SITE_KEY="$NEXT_PUBLIC_RECAPTCHA_SITE_KEY" --build-arg RECAPTCHA_SECRET_KEY="$RECAPTCHA_SECRET_KEY" -t ${CI_REGISTRY}/${CI_PROJECT_PATH}/nextjs:${CI_COMMIT_SHA} ./nextjs
the docker file:
ARG BASE_IMAGE=node:14.16.0-alpine3.13
# Build
FROM $BASE_IMAGE as BUILD
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN apk add --no-cache bash git
WORKDIR /app
COPY ./package.json ./
COPY ./package-lock.json ./
RUN CI=true npm ci
COPY . ./
ARG RECAPTCHA_SECRET_KEY=recaptchasecrect_placeholder
ENV RECAPTCHA_SECRET_KEY=${RECAPTCHA_SECRET_KEY}
ARG NEXT_PUBLIC_RECAPTCHA_SITE_KEY=recaptchasitekey_placeholder
ENV NEXT_PUBLIC_RECAPTCHA_SITE_KEY=${NEXT_PUBLIC_RECAPTCHA_SITE_KEY}
RUN npm run build
# Run
FROM $BASE_IMAGE
WORKDIR /app
COPY --from=BUILD /app ./
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
EXPOSE 3000
CMD ["npm", "start"]
If I put ENV RECAPTCHA_SECRET_KEY=my-secret-key... hardcoded into the dockerfile above EXPOSE 3000 it will work and the .env variable is available at runtime.
Why is my NEXT_PUBLIC_RECAPTCHA_SITE_KEY variable available at runtime and my RECAPTCHA_SECRET_KEY variable that is set the same way not?
When you run the next app, the variables in .evn will only load to next app if they start with NEXT_PUBLIC_, remember you are not running the next app from cmd, your starting point is 'npm start' in docker which only loads env variable with names stating from "NEXT_PUBLIC"
NEXT_PUBLIC_ANALYTICS_ID=abcdefghijk
More info here - https://nextjs.org/docs/basic-features/environment-variables
Just prefix all your variables with "NEXT_PUBLIC"
NEXT_PUBLIC_RECAPTCHA_SITE_KEY=my-public-key...
NEXT_PUBLIC_RECAPTCHA_SECRET_KEY=my-secret-key...

Dockerfile: pass argument to RUN npm run build

I have a dockerfile with these lines:
ARG ENVIRONMENT
ENV ENVIRONMENT $ENVIRONMENT
RUN npm run ng build --configuration=${ENVIRONMENT}
I cant get the "RUN npm run ng build --configuration= to pass the value of $ENVIRONMENT to the npm command.
What is the syntax for this?
Per the Dockerfile ARG docs,
The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command using the --build-arg = flag.
in order to accept an argument as part of the build, we use --build-arg.
Dockerfile ENV docs:
The ENV instruction sets the environment variable to the value .
We also need to include an ENV statement because the CMD will be executed after the build is complete, and the ARG will not be available.
FROM busybox
ARG ENVIRONMENT
ENV ENVIRONMENT $ENVIRONMENT
CMD echo $ENVIRONMENT
will cause an environment variable to be set in the image, so that it is available during a docker run command.
docker build -t test --build-arg ENVIRONMENT=awesome_environment .
docker run -it test
This will echo awesome_environment.
Try changing your RUN command do this:
RUN npm run ng build --configuration=$ENVIRONMENT
This should work. Check here
Thanks.

Expand ARG value in CMD [Dockerfile]

I'm passing a build argument into: docker build --build-arg RUNTIME=test
In my Dockerfile I want to use the argument's value in the CMD:
CMD ["npm", "run", "start:${RUNTIME}"]
Doing so results in this error: npm ERR! missing script: start:${RUNTIME} - it's not expanding the variable
I read through this post: Use environment variables in CMD
So I tried doing: CMD ["sh", "-c", "npm run start:${RUNTIME}"] - I end up with this error: /bin/sh: [sh,: not found
Both errors occur when I run the built container.
I'm using the node alpine image as a base. Anyone have ideas how to get the argument value to expand within CMD? Thanks in advance!
full Dockerfile:
FROM node:10.15.0-alpine as builder
ARG RUNTIME_ENV=test
RUN mkdir -p /usr/app
WORKDIR /usr/app
COPY . .
RUN npm ci
RUN npm run build
FROM node:10.15.0-alpine
COPY --from=builder /usr/app/.npmrc /usr/app/package*.json /usr/app/server.js ./
COPY --from=builder /usr/app/config ./config
COPY --from=builder /usr/app/build ./build
RUN npm ci --only=production
EXPOSE 3000
CMD ["npm", "run", "start:${RUNTIME_ENV}"]
Update:
Just for clarity there were two problems I was running into.
1. The problem as described by Samuel P.
2. ENV values are not carried between containers (multi-stage)
Here's the working Dockerfile where I'm able to expand environment variables in CMD:
# Here we set the build-arg as an environment variable.
# Setting this in the base image allows each build stage to access it
FROM node:10.15.0-alpine as base
ARG ENV
ENV RUNTIME_ENV=${ENV}
FROM base as builder
RUN mkdir -p /usr/app
WORKDIR /usr/app
COPY . .
RUN npm ci && npm run build
FROM base
COPY --from=builder /usr/app/.npmrc /usr/app/package*.json /usr/app/server.js ./
COPY --from=builder /usr/app/config ./config
COPY --from=builder /usr/app/build ./build
RUN npm ci --only=production
EXPOSE 3000
CMD npm run start:${RUNTIME_ENV}
The problem here is that ARG params are available only during image build.
The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command using the --build-arg <varname>=<value> flag.
https://docs.docker.com/engine/reference/builder/#arg
CMD is executed at container startup where ARG variables aren't available anymore.
ENV variables are available during build and also in the container:
The environment variables set using ENV will persist when a container is run from the resulting image.
https://docs.docker.com/engine/reference/builder/#env
To solve your problem you should transfer the ARG variable to an ENV variable.
add the following line before your CMD:
ENV RUNTIME_ENV ${RUNTIME_ENV}
If you want to provide a default value you can use the following:
ENV RUNTIME_ENV ${RUNTIME_ENV:default_value}
Here are some more details about the usage of ARG and ENV from the docker docs.

Webpack app in docker needs environment variables before it can be built

New to docker so maybe I'm missing something obvious...
I have an app split into a web client and a back end server. The back end is pretty easy to create an image for via a Dockerfile:
COPY source
RUN npm install, npm run build
CMD npm run start
The already-built back end app will then access the environment variables at runtime.
With the web client it's not as simple because webpack needs to have the environment variables before the application is built. This leaves me as far as I'm aware only two options:
Require the user to build their own image from the application source
Build the web client on container run by running npm run build in CMD
Currently I'm doing #2 but both options seem wrong to me. What's the best solution?
FROM node:latest
COPY ./server /app/server
COPY ./web /app/web
WORKDIR /app/web
CMD ["sh", "-c", "npm install && npm run build && cd ../server && npm install && npm run build && npm run start"]
First, it would be a good idea for both the backend server and web client to each have their own Dockerfile/image. Then it would be easy to run them together using something like docker-compose.
The way you are going to want to provide environment variables to the web Dockerfile is by using build arguments. Docker build arguments are available when building the Docker image. You use these by specifying the ARG key in the Dockerfile, or by passing the --build-arg flag to docker build.
Here is an example Dockerfile for your web client based on what you provided:
FROM node:latest
ARG NODE_ENV=dev
COPY ./web /app/web
WORKDIR /app/web
RUN npm install \
&& npm run build
CMD ["npm", "run", "start"]
The following Dockerfile uses the ARG directive to create a variable with a default value of dev.
The value of NODE_ENV can then be overridden when running docker build.
Like so:
docker build -t <myimage> --build-arg NODE_ENV=production .
Whether you override it or not NODE_ENV will be available to webpack before it is built. This allows you to build a single image, and distribute it to many people without them having to build the web client.
Hopefully this helps you out.

Resources