docker - build from Dockerfile, RUN, CMD
访问量: 1
RUN: 可以有多个。越少越好
CMD:全篇只能有一个。
1. RUN will not ends with \, e.g.
RUN command1 \
command 2\ # 这里不要有这个 \
CMD ['tail', '-f', '/dev/null'] # wrong, CMS will be consider as the last line of RUN
2. only 1 CMD in 1 Dockerfile
example of Dockerfile:
FROM cr.loongnix.cn/library/debian:buster RUN set -eux; \ apt-get update && \ apt-get install -y --no-install-recommends \ autoconf bison build-essential \ libssl-dev libreadline-dev zlib1g-dev \ libyaml-dev libncurses5-dev libffi-dev \ libgdbm-dev libdb-dev wget && \ \ wget https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.1.tar.gz && \ echo "fe6e4782de97443978ddba8ba4be38d222aa24dc3e3f02a6a8e7701c0eeb619d ruby-3.1.1.tar.gz" | sha256sum --check --strict && \ tar -xzf ruby-3.1.1.tar.gz && \ cd ruby-3.1.1 && \ ./configure \ --prefix=/usr/local \ --enable-shared \ --disable-install-doc \ --with-opt-dir=/usr/local/lib \ --host=loongarch64-linux-gnu \ CFLAGS="-march=loongarch64 -O2" && \ make -j$(nproc) && \ make install && \ # remove useless files cd / && \ rm -rf ruby-3.1.1 && \ rm -rf ruby-3.1.1.tar.gz && \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false && \ rm -rf /var/lib/apt/lists/* # Default command (keep container running) CMD ["irb"]

deepseek answer:
In Dockerfiles, the **`RUN` command ends when the current line ends** (unless you use line continuation with `\`). However, the behavior differs slightly depending on whether you use: ### **1. Shell Form (Default)** ```dockerfile RUN command1 ; command2 ; command3 ``` - **Ends at newline** unless escaped with `\`. - **`;` separates multiple commands in a single `RUN`** (like in Bash). - **Example**: ```dockerfile RUN echo "Hello" ; echo "World" ``` → Runs **two commands** in **one layer**. ### **2. Exec Form (JSON Array)** ```dockerfile RUN ["executable", "arg1", "arg2"] ``` - **Must be a valid JSON array**. - **No `;` needed** (each array element is an argument). - **Example**: ```dockerfile RUN ["/bin/bash", "-c", "echo Hello && echo World"] ``` ### **Key Differences** | Feature | Shell Form (`RUN cmd`) | Exec Form (`RUN ["cmd"]`) | |-----------------|----------------------|--------------------------| | **Command separator** | `;` or `&&` | Must use `&&` inside a shell | | **Variable expansion** | Yes (e.g., `$PATH`) | No (unless via shell) | | **Shell processing** | Uses `/bin/sh -c` | Direct execution | | **Line continuation** | `\` at end of line | Not applicable (JSON) | --- ### **Best Practices** 1. **Prefer `&&` over `;`** (fails fast on errors): ```dockerfile RUN apt-get update && \ apt-get install -y curl ``` 2. **Use `\` for multi-line readability**: ```dockerfile RUN apt-get update \ && apt-get install -y \ curl \ wget ``` 3. **Avoid unnecessary `;`** (can hide errors): ```dockerfile # ❌ Risky (continues even if `cmd1` fails) RUN cmd1 ; cmd2 # ✅ Better (stops if `cmd1` fails) RUN cmd1 && cmd2 ``` --- ### **Your Case Fix** Your original issue (`CMD` inside `RUN`) happened because: ```dockerfile RUN make install; \ CMD ["tail", ...] # ❌ "CMD" is not a shell command ``` → **Solution**: Move `CMD` outside `RUN`. --- ### **Summary** - `RUN` ends at newline (unless `\` continues it). - `;` separates commands **within** a single `RUN`. - **For Docker instructions** (like `CMD`, `COPY`), always put them at the top level—never inside `RUN`.