Switch language
zh
Switch theme
Light

dockerfile中CMD和RUN的区别

背景: 在使用 docker-compose 构建镜像时, 对 nextjs service 执行 RUN npm install 报错, 找不到 package.json 文件 原因: volume 中共享的文件夹, 是在容器启动时才开始共享, 在构建时没有共享, 导致 RUN 找不到 package.json, 而 CMD 才是容器运行时执行的命令

在 Dockerfile 中,CMD 和 RUN 是两个不同的指令,它们用于不同的目的和阶段:

RUN

- 用途:RUN 指令用于在构建 Docker 镜像时执行命令。
- 执行阶段:它在 Docker 镜像的构建过程中运行,生成一个新的镜像层。
- 结果:RUN 命令的结果被永久保存在镜像中,成为镜像的一部分。每次执行 RUN 时,都会创建一个新的镜像层。
- 常见用途:
    - 安装软件包和依赖项。
    - 下载和解压文件。
    - 编译源代码。
    - 创建目录和文件。
    - 配置环境和系统设置。

CMD

- 用途:CMD 指令用于指定容器启动时要执行的命令。
- 执行阶段:它在容器启动时运行,而不是在镜像构建时。
- 结果:CMD 命令的结果不会保存在镜像中,因为它是容器运行时的指令。
- 常见用途:
    - 运行应用的主进程。
    - 执行容器的默认命令。
    - 可以被 docker run 命令中的命令覆盖。

配置示例

# .env
###########################################################
###################### General Setup ######################
###########################################################

### Paths #################################################

# Choose storage path on your machine. For all storage systems
DATA_PATH_HOST=~/.dock/data

### Drivers ################################################

# All volumes driver
VOLUMES_DRIVER=local

# All Networks driver
NETWORKS_DRIVER=bridge

### Docker compose files ##################################

# Select which docker-compose files to include. If using docker-sync append `:docker-compose.sync.yml` at the end
COMPOSE_FILE=docker-compose.yml

# Change the separator from : to ; on Windows
COMPOSE_PATH_SEPARATOR=:

# Define the prefix of container names. This is useful if you have multiple projects that use laradock to have separate containers per project.
COMPOSE_PROJECT_NAME=dock

### Docker Host IP ########################################

# Enter your Docker Host IP (will be appended to /etc/hosts). Default is `10.0.75.1`
DOCKER_HOST_IP=10.0.75.1

###########################################################
################ Containers Customization #################
###########################################################

### MYSQL #################################################

# 5.7, 8.0, 8.4, 9.0
MYSQL_VERSION=8.4
MYSQL_DATABASE=default
MYSQL_USER=default
MYSQL_PASSWORD=secret
MYSQL_PORT=13306
MYSQL_ROOT_PASSWORD=root
MYSQL_TIMEZONE=UTC
MYSQL_ENTRYPOINT_INITDB=./mysql/docker-entrypoint-initdb.d

### NEXT #################################################
NODE_VERSION=22
NEXT_PORT=13300
# docker-compose.yml
networks:
  frontend:
    driver: ${NETWORKS_DRIVER}
  backend:
    driver: ${NETWORKS_DRIVER}
volumes:
  mysql:
    driver: ${VOLUMES_DRIVER}
  next:
    driver: ${VOLUMES_DRIVER}

services:
### MySQL ################################################
    mysql:
      restart: always
      build:
        context: ./mysql
        args:
          - MYSQL_VERSION=${MYSQL_VERSION}
      environment:
        - MYSQL_DATABASE=${MYSQL_DATABASE}
        - MYSQL_USER=${MYSQL_USER}
        - MYSQL_PASSWORD=${MYSQL_PASSWORD}
        - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
        - TZ=${MYSQL_TIMEZONE}
      volumes:
        - ${DATA_PATH_HOST}/mysql:/var/lib/mysql
        - ${MYSQL_ENTRYPOINT_INITDB}:/docker-entrypoint-initdb.d
      ports:
        - "${MYSQL_PORT}:3306"
      networks:
        - backend

### next #####################################################
    next:
      restart: always
      depends_on:
        - mysql
      build:
        context: ./next
        args:
          - NODE_VERSION=${NODE_VERSION}
      ports:
        - "${NEXT_PORT}:3000"
      container_name: next
      stdin_open: true
      networks:
          - frontend
          - backend
      volumes:
        - ./next:/usr/src/app/next
        - /usr/src/app/next/node_modules
# next/dockerfile
ARG NODE_VERSION
FROM node:${NODE_VERSION}-alpine

WORKDIR /usr/src/app/next

RUN \
    apk update && apk add --no-cache openssl && \
    npm config set registry https://registry.npmmirror.com && \
    npm install -g pnpm

# 创建并写入脚本文件
RUN \
    echo '#!/bin/sh' > /entrypoint.sh && \
    echo 'npm install' >> /entrypoint.sh && \
    echo 'npm run dev' >> /entrypoint.sh && \
    chmod +x /entrypoint.sh

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

ENTRYPOINT ["/entrypoint.sh"]ARG NODE_VERSION
🍀