5

I have mostly seen people using following type of pipeline steps(it varies, but in general this is the flow of steps I have observed)

Process: clone repo -> build -> test -> create docker image -> push binary to artifactory -> push image to docker registry

Recently I came across a docker file (multi-stage docker file) which was executing gradle build and test while building image.

I wanted to reach out to this community and check what are the advantages/dis-advantages of having a docker file which does gradle/maven build and test as a part of docker build?

Please Guide

2 Answers 2

2

I don't know if this is a good practice or not, but I usually create 2 docker files. One just runs the application and the other runs a multi-stage build (including test), the latter is only used by the developer, the former is the one used on CI.

The CI steps depend mostly on what language is the code, what types of tests you want to run, and what process (or development flow) the company use.

For a compiled language (like java or golang):

tests that does not need to build the code (unit tests, SAST..) --> build (the code and the container image if needed) --> tests that need a runnable version of the code (end-to-end) --> artifact repository

For a non compiled language (like php or python): tests --> tag

1
  • When we run the build in a docker process (during docker build) how do we get test reports etc.? Also it's possible to run different tasks in parallel in Jenkins e.g. you can run unit tests, component tests and integration test all together and the final build status can be concluded based on outcome of all 3. How would you achieve something of that sort with this?
    – dev2d
    Aug 1, 2021 at 5:23
0

It would be consistent with most other languages' setups to run gradle build in a Dockerfile. You may want to set up a multi-stage build so that the first stage has a complete JDK, COPYs in the build.gradle and source code, and builds it; and then the second stage only contains the JRE and the jar file COPY --from= the first stage. (Java is unusual in that it's possible to build a portable jar file outside Docker and COPY it directly into an image; most other languages either interpret the source directly, or build a native artifact that's not as portable.)

The advantages of doing this are IMHO somewhat minimal. If you have a multi-language environment, being able to git clone; docker build every service the same way is useful. You will use the JVM specified by the Dockerfile's FROM line, instead of what's installed on the host, but you will probably need a JVM anyways for day-to-day development and IME the precise patch level of the JRE isn't that important in practice.


I would not run tests in a Dockerfile.

At a philosophical level, they don't really belong there. The Dockerfile has one task: it takes source files or a jar file in, and produces a Docker image out. The Dockerfile system is designed for it to be hard for there to be side effects, so it's very difficult to start a support process or access a database even if you otherwise would want to. Running tests are in some way a "side effect" like this.

Mechanically, it makes sense to run tests both before and after the image build, but not necessarily during. You can break your tests into unit tests and integration tests. The unit tests should only depend on your application code, with mocks for any external dependencies; since they don't depend on anything but the code and the JRE, you should get consistent results whether you run them on the host or in a container, and you can first run unit tests and then only build the image if they pass. The integration tests depend on the entire system, including things you can't connect to from the Dockerfile, and so a good practice here is to run integration tests against the built image as you're about to ship it.

   Source code      (checked in to a repository)
        |
        v
   Unit tests       (on the host, no external dependencies)
        |
        v
Docker image build  (push to a repository now if needed)
        |           (only this step is the Dockerfile)
        v
Integration tests   (on the built container, with dependencies
        |            running in other containers, either launched
        v            from the host or a dedicated test-runner container)
     Deploy

I would avoid complex Dockerfiles that have multiple optional stages that sometimes include test frameworks and sometimes don't. Build one image and run it in all environments, and keep the Dockerfile simple and readable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.