About the matter that tends to be confused with ARG of Dockerfile which is a multi-stage build

TL;DR

If you use ARG with a multi-stage build Dockerfile, be aware that the scope is closed inside the stage! Declare the ARG to use for each stage! Also, if the ARG used in multiple stages has a default value, define a global ARG and put the default value there!

It's okay if you make it like this!

Dockerfile


#If there is a default value for the ARG that is commonly used in each stage, define it before the first FROM.
ARG YOUR_ARG="Default value"

FROM alpine:latest as first_stage
#ARG must be declared for each stage used.
ARG YOUR_ARG
RUN echo "1st stage: ${YOUR_ARG}"

FROM alpine:latest as second_stage
#ARG must be declared for each stage used.
ARG YOUR_ARG
RUN echo "2nd stage: ${YOUR_ARG}"

About the relationship between multi-stage build and ARG

In multi-stage builds, the scope of ARG and ENV seems to be limited per stage. Did you all know? I didn't know until I realized that I couldn't refer to the ARG value in the stage of the Dockerfile I made.

According to this comment

Correct, Dockerfile instructions, including ENV vars and ARG are scoped per build-stage, and will not be preserved in the next stage; this is by design. You can, however, set a global ARG (set before the first build-stage), and use that value in each build-stage; Dockerfile instructions, including ENV and ARG, are scoped for each build stage and will not be carried over to the next stage. This is what it is by design. However, if you use a global ARG (defined before the first build stage), you can take advantage of that value for each build stage.

... apparently ... Really?

It was also firmly listed in the Official Document.

The variable scope of an ARG instruction is until the end of the build stage in which it is defined. If you want to use ARG in multiple build stages, you need to specify the ARG instruction individually.

When I first read the document, I felt like I thought, "Ahhhhh, I completely understood it," without knowing the meaning of the build stage. .. ..

Let's see the movement of ARG

Let's actually see how ARG works in a multi-stage build.

Operation check environment of this paper

At the time of writing this article, we have confirmed the operation with the following versions.

# docker --version
Docker version 18.09.1, build 4c52b90

Dockerfile

The Dockerfile used in this verification is as follows.

Dockerfile


#ARG1 declares globally and sets global default values.
ARG ARG1="arg1 global default value"
#ARG2 declares globally but does not set a global default value.
ARG ARG2
#ARG3 does not declare globally.
# ARG ARG3


FROM alpine:latest as first_stage

# first_In stage, each ARG is declared and the default value in scope is set.
ARG ARG1="arg1 first stage value"
ARG ARG2="arg2 first stage value"
ARG ARG3="arg3 first stage value"
RUN echo -e "first_stage:\n\tARG1=${ARG1}\n\tARG2=${ARG2}\n\tARG3=${ARG3}"


FROM alpine:latest as second_stage

# second_The stage declares each ARG but does not set a default value in scope.
ARG ARG1
ARG ARG2
ARG ARG3
RUN echo -e "second_stage:\n\tARG1=${ARG1}\n\tARG2=${ARG2}\n\tARG3=${ARG3}"


FROM alpine:latest as third_stage

# third_At stage, do not declare all ARGs.
# ARG ARG1
# ARG ARG2
# ARG ARG3
RUN echo -e "third_stage:\n\tARG1=${ARG1}\n\tARG2=${ARG2}\n\tARG3=${ARG3}"

Each ARG is set as follows.

ARG name Settings
ARG1 Set as a global ARG. Also specify the default value.
ARG2 Set as a global ARG. No default value is specified.
ARG3 Do not set as a global ARG.

In addition, each stage is set as follows.

Stage name Settings
first_stage Declare each ARG. Set the default value in the stage.
second_stage Declare each ARG. Do not set default values in the stage.
third_stage Do not declare ARG.

--build-arg Build without specification

When building Docker Image, try building without specifying the value with --build-arg.

# docker build . --no-cache
Sending build context to Docker daemon  14.85kB
...snip...
Step 7/14 : RUN echo -e "1st stage:\n\tARG1=${ARG1}\n\tARG2=${ARG2}\n\tARG3=${ARG3}"
 ---> Running in 2bbe78634ee8
first_stage:
        ARG1=arg1 first stage value
        ARG2=arg2 first stage value
        ARG3=arg3 first stage value
...snip...
Step 12/14 : RUN echo -e "2nd stage:\n\tARG1=${ARG1}\n\tARG2=${ARG2}\n\tARG3=${ARG3}"
 ---> Running in 0c28af93ea9b
second_stage:
        ARG1=arg1 global default value
        ARG2=
        ARG3=
...snip...
Step 14/14 : RUN echo -e "3rd stage:\n\tARG1=${ARG1}\n\tARG2=${ARG2}\n\tARG3=${ARG3}"
 ---> Running in cbca9ed88691
third_stage:
        ARG1=
        ARG2=
        ARG3=
...snip...

--build-arg Build with specification

Now try building with the value specified by --build-arg.

# docker build --build-arg ARG1="build arg1 value" --build-arg ARG2="build arg2 value" --build-arg ARG3="build arg3 value" . --no-cache
Sending build context to Docker daemon  14.85kB
...snip...
Step 7/14 : RUN echo -e "1st stage:\n\tARG1=${ARG1}\n\tARG2=${ARG2}\n\tARG3=${ARG3}"
 ---> Running in 10b37c5a524b
first_stage:
        ARG1=build arg1 value
        ARG2=build arg2 value
        ARG3=build arg3 value
...snip...
Step 12/14 : RUN echo -e "2nd stage:\n\tARG1=${ARG1}\n\tARG2=${ARG2}\n\tARG3=${ARG3}"
 ---> Running in e70e3ff9fe9b
second_stage:
        ARG1=build arg1 value
        ARG2=build arg2 value
        ARG3=build arg3 value
...snip...
Step 14/14 : RUN echo -e "3rd stage:\n\tARG1=${ARG1}\n\tARG2=${ARG2}\n\tARG3=${ARG3}"
 ---> Running in e675e8f648e8
third_stage:
        ARG1=
        ARG2=
        ARG3=
...snip...

Summary

  1. Value specified by --build-arg [High priority]
  2. Default value in stage
  3. Global default value [Low priority]

That's it.

Promotion

This is a promotion of the project that triggered me to notice the behavior of ARG in multi-stage build.

Let's operate Minecraft's Bedrock Server easily! This is a project to the effect. Minecraft occasionally updates, but the client is mostly updated on its own, but Bedrock Server is not updated automatically, manually downloading the new version, unzipping the Zip file and extracting the binary file I had to replace it and restart the service ... or something. This project will update Bedrock Server automatically once you set it up! By the way, Docker is used to build Bedrock Server, so it doesn't pollute the environment!

Thank you!

Really done.

Recommended Posts

About the matter that tends to be confused with ARG of Dockerfile which is a multi-stage build
About the matter that I was addicted to how to use hashmap
About the matter that tends to be confused with ARG of Dockerfile which is a multi-stage build
[Android Studio] About the matter that the design view is not displayed when using TextClock
About the matter that hidden_field can be used insanely
Determine that the value is a multiple of 〇 in Ruby
A memo of the program that allows you to realize that the probability of dice rolling is about 1/6
[Docker] Is it good enough to call it a multi-stage build? → The story that became so good
How to build an environment with Docker, which is the minimum required to start a Rails application
The story of making it possible to build a project that was built by Maven with Ant
About the matter that hidden_field can be used insanely
Determine that the value is a multiple of 〇 in Ruby
Be sure to compare the result of Java compareTo with 0
A collection of patterns that you want to be aware of so as not to complicate the code
About the solution to the problem that the log of logback is not output when the web application is stopped
[Be careful about changing the version of Xdebug! ] Create a development environment with Xdebug3 + docker + VS Code
What to do about the "cannot be read or is not a valid ZIP file" error
How to deal with the type that I thought about writing a Java program for 2 years
I tried to solve the problem of "multi-stage selection" with Ruby
A story about hitting the League Of Legends API with JAVA
About the matter that I was addicted to how to use hashmap
A story that struggled with the introduction of Web Apple Pay
How to identify the path that is easy to make a mistake
[Java] You might be happy if the return value of a method that returns null is Optional <>
A story that I was addicted to twice with the automatic startup setting of Tomcat 8 on CentOS 8
A story that I wanted to write a process equivalent to a while statement with the Stream API of Java8
The case that "apt-get update" defined in "Dockerfile" could not be done at the time of "docker-compose build"
A memo that was soberly addicted to the request of multipart / form-data
How to interact with a server that does not crash the app
About the problem that the server can not be started with rails s
To you who lament that the conversion of JODConverter + LibreOffice is slow
A program that determines whether the entered integer is close to an integer
I can't build if I set the build destination to a simulator with XCode12!
A description of the JDBC Sample that will be helpful when developing a custom authentication provider with the Cognos SDK
A simple application (CT) that allows you to view the RDSR in which the radiation exposure dose is recorded.
I tried to make a program that searches for the target class from the process that is overloaded with Java
What to do about "A server is already running ..." that happened without turning off the rails server in the terminal
I tried to make a web application that searches tweets with vue-word cloud and examines the tendency of what is written in the associated profile