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`.

订阅/RSS Feed

Subscribe