Do I need separate Dockerfiles for py2 and py3? - docker

Currently I have 2 Dockerfiles, Dockerfile-py2:
FROM python:2.7
# stuff
and Dockerfile-py3:
FROM python:3.4
# stuff
where both instances of # stuff are identical.
I build two docker images using an invoke task:
#task
def docker(ctx):
"""Build docker images.
"""
tag = ctx.run('git log -1 --pretty=%h').stdout.strip()
for pyversion in '23':
name = 'myrepo/myimage{pyversion}'.format(pyversion=pyversion)
image = '{name}:{tag}'.format(name=name, tag=tag)
latest = '{name}:latest'.format(name=name)
ctx.run('docker build -t {image} -f Dockerfile-py{pyversion} .'.format(image=image, pyversion=pyversion))
ctx.run('docker tag {image} {latest}'.format(image=image, latest=latest))
ctx.run('docker push {name}'.format(name=name))
is there any way to prevent the duplication of # stuff so I can't get in a situation where someone edits one file but not the other?

Here is one way using Dockerfile ARGS along with docker build --build-arg:
ARG version
FROM python:${version}
RUN echo "$(python --version)"
# stuff
Now you build for python2.7 like so:
docker build -t myimg/tmp --build-arg version=2.7 .
In the output you will see:
Step 3/3 : RUN echo "$(python --version)"
---> Running in 06e28a29a3d2
Python 2.7.16
And in the same way, for python3.4:
docker build -t myimg/tmp --build-arg version=3.4 .
In the output you will see:
Step 3/3 : RUN echo "$(python --version)"
---> Running in 2283edc1b65d
Python 3.4.10
As you can imagine you can also set default values for ${version} in your dockerfile:
ARG version=3.4
FROM python:${version}
RUN echo "$(python --version)"
# stuff
Now if you just do docker build -t myimg/tmp . you will build for python3.4. But you can still override with the previous two commands.
So to answer your question, No, you don't need two different docker files.

Related

why get error: "docker build" requires exactly 1 argument

I look a sample
Dockerfile
ARG some_variable_name
# or with a default:
# ARG some_variable_name=default_value
RUN echo "Oh dang look at that $some_variable_name
# or with ${some_variable_name}
docker build
$ docker build --build-arg some_variable_name=a_value
result
Oh dang look at that a_value
but, I used the sample always gets error
"docker build" requires exactly 1 argument.
See 'docker build --help'.
Usage: docker build [OPTIONS] PATH | URL | -
Build an image from a Dockerfile
Why? Was I lose something?
in addition to #Ridwan answer, MAKE SURE THERE IS NO ADDITIONAL WHITE SPACE IN BETWEEN
docker build -t mytag .
You seem to have forgotten to put a dot, which represents that the Dockerfile in the local directory.
By that I meant:
docker build -t mytag .
What you were previously doing was:
docker build -t mytag
Thus forgetting to put the dot.

Switch environment in docker file instead of in maven command

I am trying to run parallel builds using jenkins file and docker . I am currently able to run maven commands by putting a -f tag in maven command. I however want to move this in docker to decouple that from jenkinsfile
I tried adding WORKDIR in dockerfile and trying to switch
I tried using this in copyDocker.inside with "-w /containerworkspace" no luck
dockerfile
ARG BASE
FROM artifactory.XXX.XXXX.com/${BASE}
ADD . /containerworkspace/
RUN chmod -R 777 /containerworkspace
jenkinsfile code
def builtImage = self.docker.build(
"${imageName}:${branchNumber}-${buildNumber}",
" --build-arg BASE=${imageName}"
+ " -f ${dockerFile}")
BBDocker copyDocker = dockerBuild.clone()
copyDocker.image("${imageName}:${branchNumber}-${buildNumber}").inside (){
self.sh("mvn -U clean install -f /containerworkspace/")
}
I am trying to eliminate -f /containerworkspace/ from maven and put it into docker file somehow.

Execute ENTRYPOINT from base image in build stage

I'm using a code generator tool which is provided as a Docker image with an ENTRYPOINT. I.e. for the manual use case I execute the following command line:
$ docker run --rm -v ${PWD}:/local some/codegen-image:latest \
generate ... parameters for code generator tool ...
So far, so good.
But I want to integrate the code generator image into my own multi-stage image build. I.e. the first stage should call the ENTRYPOINT of the base image to generate the code that will be consumed by the second stage:
# stage 1
FROM some/codegen-image:latest as codegen
... build set up steps for stage 1 ...
# now run ENTRYPOINT from base image, copy & pasted from the output of
#
# docker inspect -f '{{json .Config.Entrypoint}}' some/codegen-image:latest
#
RUN ["some_command", "option1", ..., "optionN", \
"generate", \
... parameters for code generator tool ... \
]
# stage 2
FROM some/other-image as stage2
... build set up steps for stage 2 ...
# copy-in generated code from stage 1
COPY --from=codegen /tmp/build/ .
This works but it violates the DRY principle, i.e. I need to update my Dockerfile every time the upstream project makes an incompatible change to its ENTRYPOINT.
Can I avoid the copy & paste from docker inspect output? My own research has turned up nothing so far...
Multi-Stage Dockerfile was introduced to optimize the overall size of the container docs.
The FROM directive just brings the content of the image specified, but you have to explicitly tell the container what command should be executed.
The feature you are expecting is not yet supported by docker.
Eg.
FROM some/codegen-image:latest as codegen
ARGS_ENTRYPOINT_OF_CODEGEN ["generate","parameters"]
.
.
.
FROM some/other-image as stage2
COPY --from=codegen /tmp/build/ .
It seems your approach is correct at this moment and the only way around.

Is there a way to use If condition in Dockefile?

I am new to docker, I am looking for a way to execute a command in docker container depends on the environment.
In Dockerfile, I have 2 commands, command_a and command_b. If the env = 'prod' run command_a, else command_b. How can I achieve this?
I tried like below:
RUN if [ $env = "prod" ] ; then echo command_a; else echo cpmmand_b; fi;
How can I achieve the desired behaviour?
PS:
I know that echo should not be there.
Docker 17.05 and later supports a kind of conditionals using multi-stage build and build args. Have a look at https://medium.com/#tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae
From the blog post:
ARG BUILD_VERSION=1
FROM alpine AS base
RUN ...
FROM base AS branch-version-1
RUN touch version1
FROM base AS branch-version-2
RUN touch version2
FROM branch-version-${BUILD_VERSION} AS after-condition
FROM after-condition
RUN ...
And then use docker build --build-arg BUILD_VERSION=value ...

Docker Conditional build image

I have to execute the same script to two docker images.
My Dockerfile are:
FROM centos:6
...
and
FROM centos:7
...
Is it possibile to have a single file and pass a parameter, something like:
FROM centos:MYPARAMS
and during the build somethings like that:
docker build --no-cache MYPARAMS=6 .
Thank you
Just to put this in right context, it is now (since May 2017) possible to achieve this with pure docker since 17.05 (https://github.com/moby/moby/pull/31352)
Dockerfile should look like (yes, commands in this order):
ARG APP_VERSION
ARG GIT_VERSION
FROM app:$APP_VERSION-$GIT_VERSION
Then build is invoked with
docker build --build-arg APP_VERSION=1 --build-arg GIT_VERSION=c351dae2 .
Docker will try to base the build on image app:1-c351dae2
Helped me immensely to reduce logic around building images.
From my knowledge, this is not possible with Docker.
The alternative solution is to use a Dockerfile "template", and then parse it using the template library of your choice. (Or even using sed command)
At https://github.com/BITPlan/docker-stackoverflowanswers/tree/master/33351864
you'll find a bash script "build" that works the way you want.
wf#mars:~/source/docker/docker-stackoverflowanswers/33351864>./build -v 6
Sending build context to Docker daemon 3.584 kB
Step 0 : FROM centos:6
6: Pulling from library/centos
fa5be2806d4c: Pull complete
ebdbe10e9b33: Downloading 4.854 MB/66.39 MB
...
wf#mars:~/source/docker/docker-stackoverflowanswers/33351864>./build -v 7
Sending build context to Docker daemon 3.584 kB
Step 0 : FROM centos:7
The essential part is the "here" document used:
#
# parameterized dockerfile
#
dockerfile() {
local l_version="$1"
cat << EOF > Dockerfile
FROM centos:$l_version
EOF
}

Resources