Docker 入门指南


Docker 入门指南

目录
  • Docker 入门指南
  • 1 环境准备
    • 1.1 安装docker/getting-started
    • 1.2 Docker术语
      • 1.2.1 容器(Container)
      • 1.2.2 镜像(Image)
      • 1.2.3 Volume
  • 2 创建一个App容器镜像
    • 2.1 下载APP源代码
    • 2.2 编写Dockerfile
  • 3 更新App源代码
  • 4 共享App镜像
    • 4.1 创建一个repo
    • 4.2 推送App镜像
    • 4.3 运行App镜像新实例
  • 5 持久化数据
    • 5.1 容器的文件系统
    • 5.2 持久化ToDo数据
      • 5.2.1 named volume
      • 5.2.2 bind mounts
  • 6 多容器 Apps
    • 6.1 配置原则:让每个容器只做好一件事
    • 6.2 配置多容器运行应用
      • 6.2.1 配置Mysql容器
      • 6.2.2 MySQL容器网络状态
      • 6.2.3 利用MySQL容器运行App程序
  • 7 使用Docker Compose
    • 7.1 创建Compose文件
    • 7.2 定义App服务
    • 7.3 定义MySQL服务
    • 7.4 运行应用程序栈
  • 8 创建image最佳实践
  • 8.1 image层
    • 8.2 层缓存

Docker Documentation | Docker Documentation

image-20220307090634652

1 环境准备

1.1 安装docker/getting-started

$ docker run -d -p 80:80 docker/getting-started

# 也可以执行以下命令
$ docker run -dp 80:80 docker/getting-started
  • -d - 后台运行容器
  • -p 80:80 - 映射主机80端口
  • docker/getting-started - 要使用的镜像

1.2 Docker术语

1.2.1 容器(Container)

容器是指一个独立于主机上其他所有进程的沙箱进程。Docker使用kernal namespaces和cgroup来提供容器隔离。

  • 通过DockerAPI 或 CLI可以运行的镜像实例,可以创建、启动、停止、移动或删除。
  • 可以运行在本地主机、虚拟机、云上
  • 可以运行在任何系统上
  • 容器之间相互独立,每个容器的运行环境、配置、软件等也相互独立。

1.2.2 镜像(Image)

当运行一个容器时需要一个独立的文件系统。这个系统是容器镜像提供的。因为镜像包含容器的文件系统,因此镜像必须包含运行一个应用程序的所有依赖环境。

1.2.3 Volume

  1. 容器卷(Volumes):Volumes用于持久化数据。默认情况下,容器所有的配置是各自独立的,因此当容器被删除时,配置也会丢失。容器卷可以将容器特定文件系统路径回连到主机,如果目录被挂载,在当前目录所做的更改会同步到本地。即只要启动新容器时挂载相同的目录,就能查看到目录中的文件。

  2. 绑定挂载(bind mounts):bind mounts用于持久化数据。通过bind mounts可以精确控制主机上的挂载点,也可能用于为容器提供额外的数据。
    对于应用程序:利用bind mounts挂载源代码到容器可以实时看到代码的变化和回包。
    对于基于节点的应用程序:nodemon可以更好的监控应用程序重启时的文件变化。

  3. Volumes与bind mounts对比

    Named Volumes Bind Mounts
    主机位置 Docker 决定 自定义
    挂载示例(-v) my-volume:/usr/local/data /path/to/data:/usr/local/data
    作为新卷挂载到容器 Yes No
    支持Volume Drivers Yes No

2 创建一个App容器镜像

2.1 下载APP源代码

  1. 确保前面设置的docker容器正常运行。
  2. 下载地址:http://yourIP/assets/app.zip
  3. 解压app.zip。

2.2 编写Dockerfile

Dockerfile 类似一个创建容器镜像的文本脚本说明书。

  1. package.json同个目录下创建一个名称为Dockerfile的文件,内容如下:

    FROM node:12-alpine
    # Adding build tools to make yarn install work on Apple silicon / arm64 machines
    RUN apk add --no-cache python2 g++ make
    WORKDIR /app
    COPY . .
    RUN yarn install --production
    CMD ["node", "src/index.js"]
    

    注:Dockerfile文件不能有任何后缀,否则会报错。

  2. 创建容器镜像

    docker build -t getting-started .
    

    image-20220307105936431

    • 之所以会下载许多的layers,是因为我们指定了要从node:12-alpine开始创建,由于我们系统中不存在,所以需要下载。
    • 下载完成后,首先复制应用程序,其次使用yarn安装应用程序的依赖,以上命令使用了默认的命令从该镜像中启动一个容器。
    • -t参数:命令该镜像为:getting-started
    • .告诉Docker使用本地的Dockerfile
  3. 启动App容器

    docker run -dp 3000:3000 getting-started
    

    image-20220307141239376

  4. 访问http://yourIP:3000/可以访问创建好的App,并创建两个Items

    image-20220308093809494

3 更新App源代码

  1. src/static/js/app.js 文件中更新内容如下:

    # 将56行数据修改成以下内容
    // 

    No items yet! Add one above!

    You have no todo items yet! Add one above!

  2. 创建App更新后的image版本

    docker build -t getting-started .
    
  3. 启动一个新的App容器

    # 需要先删除旧版本的App容器
    # 停止App容器
    docker stop 
    # 删除App容器
    docker rm 
    # 一次命令停止并删除App容器
    docker rm -f 
    
    docker run -dp 3000:3000 getting-started
    

    image-20220307150907477

4 共享App镜像

4.1 创建一个repo

在共享一个镜像之前,我们需要在Docker Hub上创建一个repo

  1. 进入Docker Hub

  2. 选择 Create Repository

  3. repo名称: getting-started

  4. 确保可见为公共后点击创建

    docker push fcarey/getting-started:tagname
    

    image-20220307152648530

4.2 推送App镜像

  1. 命令行模式

    docker push fcarey/getting-started:tagname
    The push refers to repository [docker.io/fcarey/getting-started]
    An image does not exist locally with the tag: fcarey/getting-started
    

    提示错误:该命令将会查找本地fcarey/getting-started镜像,但是没有找到。可以通过docker image ls 查看本地存在的镜像。要解决该问题,需要给已经存在的镜像打tag。

  2. 命令行登录Docker Hub

    docker login -u YOUR-USER-NAME
    

    image-20220307153748441

  3. 使用 docker tag命令给 getting-started 镜像打tag,记得前缀换成你自己的Docker ID。

    docker tag getting-started YOUR-USER-NAME/getting-started
    

    image-20220307155245417

  4. 如果不想配置镜像的tagname,默认为: latest

    docker push YOUR-USER-NAME/getting-started
    

4.3 运行App镜像新实例

  1. 浏览器打开labs.play-with-docker.com,并登录

  2. 点击左侧"+ ADD NEW INSTANCE"

  3. 在终端中启动刚刚推送的App镜像

    docker run -dp 3000:3000 YOUR-USER-NAME/getting-started
    

    image-20220307160643824

  4. 点击"Open Port" 按钮,输入3000查看你所修改的App。

    image-20220307160703001

5 持久化数据

更新镜像后,新的App容器中并没有旧App容器所创建的数据,为什么呢?

5.1 容器的文件系统

当容器运行时,会使用不同layers,每个容器都会创建各自的暂存空间,即使使用相同的镜像,每个容器也是互不影响。

  1. 启动一个新容器

    docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
    
    • 启动新容器的同时,开启一个bash shell ,并插入两个命令
    • shuf -i 1-10000 -n 1 -o /data.txt 为随机生成1个在1-10000之间的数并保存在/data.txt文件中
    • tail -f /dev/null 查看/dev/null最新的日志记录
  2. 命令行查看/data.txt内容,会看到一个随机的数字

    sudo docker exec  cat /data.txt
    

    image-20220308090645544

  3. 使用相同的镜像启动另外一个ubuntu容器,并容器中并不存在data.txt文件

    docker run -it ubuntu ls /
    

    image-20220308090443703

  4. 删除第一个容器

    docker rm -f 
    
  5. 结论:容器所有的配置是各自独立的,因此当容器被删除时,配置也会丢失。

5.2 持久化ToDo数据

默认情况下,App容器的数据保存在 /etc/todos/todo.db,即SQLite数据库中。通过创建volume并挂载相应目录可以实现持久化数据。

5.2.1 named volume

适用于只是保存数据但并不关心数据的存储位置。

  1. 创建volume

    docker volume create todo-db
    
  2. 停止并删除之前所创建的App容器

    docker rm -f 
    
  3. 启动新的App容器,命令如下:

    docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
    
    • -v:指定要挂载的卷名:要挂载到容器的目录
  4. 启动容器后,打开App并添加一些ToDo清单

    image-20220308100651130

  5. 删除刚刚创建的App容器

    docker rm -f 
    
  6. 使用第3步命令启动一个新的App容器

  7. 打开App后,我们之前创建的数据还在

    image-20220308100651130

  8. 查看named volume实际存放数据的位置

    docker volume inspect todo-db
    

    image-20220308101620311

5.2.2 bind mounts

适用于保存数据并指定数据存储位置;通过物理主机修改容器中相应程序的配置文件。

  1. 以创建一个开发模式的容器为例

    创建开发模式的容器的条件:
    
    1. 挂载源码到容器
    2. 安装所有依赖,包括"dev"依赖
    3. 开启nodemon监控文件系统改变
    
  2. 在源码文件目录下运行以下命令:

    docker run -dp 3000:3000 \
        -w /app -v "$(pwd):/app" \
        node:12-alpine \
        sh -c "yarn install && yarn run dev"
    
    • -dp 3000:3000:后台运行并将主机3000端口映射到容器3000端口。
    • -w /app:指定运行命令的工作目录。
    • -v "$(pwd):/app":绑定挂载主机当前的工作目录到容器的/app目录。
    • sh -c "yarn install && yarn run dev":使用shell运行yarn install安装所有依赖,然后运行yarn run dev。此时查看 package.json可以看到dev脚本启动了nodemon
  3. 查看运行日志:按 Ctrl+C退出

    ┌──(root??kali)-[/docker/app]
    └─# docker logs -f 2f788837b11a
    yarn install v1.22.17
    [1/4] Resolving packages...
    warning Resolution field "ansi-regex@5.0.1" is incompatible with requested version "ansi-regex@^2.0.0"
    warning Resolution field "ansi-regex@5.0.1" is incompatible with requested version "ansi-regex@^3.0.0"
    warning sqlite3 > node-gyp > tar@2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.
    warning sqlite3 > node-gyp > request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
    warning sqlite3 > node-gyp > request > har-validator@5.1.5: this library is no longer supported
    warning sqlite3 > node-gyp > request > uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
    [2/4] Fetching packages...
    [3/4] Linking dependencies...
    [4/4] Building fresh packages...
    success Saved lockfile.
    Done in 36.74s.
    yarn run v1.22.17
    $ nodemon src/index.js
    [nodemon] 2.0.13
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node src/index.js`
    Using sqlite database at /etc/todos/todo.db
    Listening on port 3000
    
    
  4. app/src/static/js/app.js 文件中,将"Add Item" 改成 "Add"

    -	{submitting ? 'Adding...' : 'Add Item'}
    +	{submitting ? 'Adding...' : 'Add'}
    
  5. 重新刷新页面可以看到修改成功

    image-20220317155907351

6 多容器 Apps

6.1 配置原则:让每个容器只做好一件事

独立功能的容器:

  1. 更方便的使用不同的数据库扩展API和前端
  2. 同时运行存在不同版本或更新版本的app容器。
  3. 在生产环境中使用数据库托管服务,独立发布应用。
  4. 一个容器内运行多个进程程序(每个容器只有一个进行),增加了容器的启动或关闭的复杂性。

6.2 配置多容器运行应用

配置App应用工作模式如下:

image-20220317164518171

6.2.1 配置Mysql容器

  1. 创建容器网络

    docker network create todo-app
    
  2. 启动一个Mysql容器配置如下,并连接到上面创建的容器网络中

    docker run -d \
        --network todo-app --network-alias mysql \
        -v todo-mysql-data:/var/lib/mysql \
        -e MYSQL_ROOT_PASSWORD=secret \
        -e MYSQL_DATABASE=todos \
        mysql:5.7
    
    • 使用一个名称为todo-mysql-data的volume挂载到Mysql数据存储路径/var/lib/mysql。若本地没有该name volume,docker会自动创建。
  3. 确认mysql是否正常运行:可以看上去创建的todos数据库

    docker exec -it 710257e08335 mysql -p
    # 密码为:secret
    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    | todos              |
    +--------------------+
    5 rows in set (0.00 sec)
    
    

6.2.2 MySQL容器网络状态

  1. 使用 nicolaka/netshoot 调试网络:利用nicolaka/netshoot镜像创建一个容器,并确保连接到同一个网络。

    docker run -it --network todo-app nicolaka/netshoot
    
  2. 在刚刚创建的容器中使用dig或ping命令查看主机名为MySQL的IP。

    #  dig mysql
    
    ; <<>> DiG 9.16.22 <<>> mysql
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21154
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;mysql.                         IN      A
    
    ;; ANSWER SECTION:
    mysql.                  600     IN      A       172.18.0.2
    
    ;; Query time: 0 msec
    ;; SERVER: 127.0.0.11#53(127.0.0.11)
    ;; WHEN: Thu Mar 17 09:15:55 UTC 2022
    ;; MSG SIZE  rcvd: 44
    
    # ping -c 1 mysql
    PING mysql (172.18.0.2) 56(84) bytes of data.
    64 bytes from mysql.todo-app (172.18.0.2): icmp_seq=1 ttl=64 time=0.144 ms
    

6.2.3 利用MySQL容器运行App程序

docker中所支持的MySQL环境变量:

  • MYSQL_HOST:MySQL容器主机名
  • MYSQL_USER :连接MySQL的用户名
  • MYSQL_PASSWORD :连接MySQL的用户密码
  • MYSQL_DB :指定要连接MySQL数据库名称
  1. 启动新容器并配置如下:

    docker run -dp 3000:3000 \
      -w /app -v "$(pwd):/app" \
      --network todo-app \
      -e MYSQL_HOST=mysql \
      -e MYSQL_USER=root \
      -e MYSQL_PASSWORD=secret \
      -e MYSQL_DB=todos \
      node:12-alpine \
      sh -c "yarn install && yarn run dev"
    
  2. 查看运行日志:

    docker logs 
    yarn install v1.22.17
    [1/4] Resolving packages...
    warning Resolution field "ansi-regex@5.0.1" is incompatible with requested version "ansi-regex@^2.0.0"
    warning Resolution field "ansi-regex@5.0.1" is incompatible with requested version "ansi-regex@^3.0.0"
    success Already up-to-date.
    Done in 0.68s.
    yarn run v1.22.17
    $ nodemon src/index.js
    [nodemon] 2.0.13
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node src/index.js`
    Waiting for mysql:3306.
    Connected!
    Connected to mysql db at host mysql
    Listening on port 3000
    
  3. 浏览器打开app程序并添加几个todo list

  4. 连接mysql数据库验证数据写入在MySQL数据库中

    docker exec -it  mysql -p todos
    mysql> use todos
    mysql> select * from todo_items;
    +--------------------------------------+--------+-----------+
    | id                                   | name   | completed |
    +--------------------------------------+--------+-----------+
    | 1883d865-3eae-45f1-ac72-3ff9b2e8f4cd | test01 |         0 |
    | 4db8cd95-f647-455b-87a6-380afa0208c9 | test02 |         0 |
    +--------------------------------------+--------+-----------+
    2 rows in set (0.00 sec)
    
    

7 使用Docker Compose

Docker Compose 是用于帮助定义并共享多容器应用程序的工具。通过Compose可以创建YAML文件来通过一条命令定义服务。Compose的优点是可以在保存在项目repo根中的YAML文件中定义你的应用程序的栈,并可以让任何人建设,克隆并使用你的项目。

7.1 创建Compose文件

  1. 首先确认已安装Docker Compose

    # docker-compose version                
    docker-compose version 1.29.2, build unknown
    docker-py version: 5.0.0
    CPython version: 3.9.10
    OpenSSL version: OpenSSL 1.1.1m  14 Dec 2021
    
  2. 在app项目根目录下,创建一个名称为docker-compose.yml的文件,并配置如下内容定义schema版本:

    version: "3.8"
    
    services:
    
    • 配置参考指南: Compose file reference
  3. 后面我们将迁移一个要运行服务或容器作为App应用程序的一部分

7.2 定义App服务

  1. 在前面定义app容器时,所使用的命令:

    docker run -dp 3000:3000 \
      -w /app -v "$(pwd):/app" \
      --network todo-app \
      -e MYSQL_HOST=mysql \
      -e MYSQL_USER=root \
      -e MYSQL_PASSWORD=secret \
      -e MYSQL_DB=todos \
      node:12-alpine \
      sh -c "yarn install && yarn run dev"
    
  2. 定义服务入口和容器的镜像,可以为服务指定一个名称,该名称将自动成为该容器的网络别名。

    version: "3.8"
    
    services:
      app:
        image: node:12-alpine
    
  3. 迁移定义app容器时的命令

    version: "3.8"
    
    services:
      app:
        image: node:12-alpine
        command: sh -c "yarn install && yarn run dev"
    
  4. 迁移端口映射配置:此处使用的是 short syntax ,更详细的请参考 long syntax

    version: "3.8"
    
    services:
      app:
        image: node:12-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
    
  5. 迁移工作目录:working_dir定义工作目录(-w /app); volumes 定义volume映射-v "$(pwd):/app"

    version: "3.8"
    
    services:
      app:
        image: node:12-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
        working_dir: /app
        volumes:
          - ./:/app
    
  6. 迁移环境变量设定

    version: "3.8"
    
    services:
      app:
        image: node:12-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
        working_dir: /app
        volumes:
          - ./:/app
        environment:
          MYSQL_HOST: mysql
          MYSQL_USER: root
          MYSQL_PASSWORD: secret
          MYSQL_DB: todos
    

7.3 定义MySQL服务

  1. 在前面定义MySQL容器时,所使用的命令:

    docker run -d \
      --network todo-app --network-alias mysql \
      -v todo-mysql-data:/var/lib/mysql \
      -e MYSQL_ROOT_PASSWORD=secret \
      -e MYSQL_DATABASE=todos \
      mysql:5.7
    
  2. 定义服务入口并命名为mysql

    version: "3.8"
    
    services:
      app:
        # The app service definition
      mysql:
        image: mysql:5.7
    
  3. 定义volume映射:在Compose中不会像使用 docker run命令会自动创建named volume,因此需要使用l volumes: 区块定义volume,并在服务配置中指定挂载点,若提供volume名,将使用默认选项,更多选项参考。

    version: "3.8"
    
    services:
      app:
        # The app service definition
      mysql:
        image: mysql:5.7
        volumes:
          - todo-mysql-data:/var/lib/mysql
    
    volumes:
      todo-mysql-data:
    
  4. 定义环境变量

    version: "3.8"
    
    services:
      app:
        # The app service definition
      mysql:
        image: mysql:5.7
        volumes:
          - todo-mysql-data:/var/lib/mysql
        environment: 
          MYSQL_ROOT_PASSWORD: secret
          MYSQL_DATABASE: todos
    
    volumes:
      todo-mysql-data:
    
  5. 最终的配置文件docker-compose.yml内容如下:

    version: "3.8"
    
    services:
      app:
        image: node:12-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
        working_dir: /app
        volumes:
          - ./:/app
        environment:
          MYSQL_HOST: mysql
          MYSQL_USER: root
          MYSQL_PASSWORD: secret
          MYSQL_DB: todos
    
      mysql:
        image: mysql:5.7
        volumes:
          - todo-mysql-data:/var/lib/mysql
        environment: 
          MYSQL_ROOT_PASSWORD: secret
          MYSQL_DATABASE: todos
    
    volumes:
      todo-mysql-data:
    
    

7.4 运行应用程序栈

  1. 删除之前所所创建的app与mysql容器

     docker rm -f 
    
  2. 运行应用程序栈

    docker-compose up -d
    Creating network "app_default" with the default driver
    Creating volume "app_todo-mysql-data" with default driver
    Creating app_app_1   ... done
    Creating app_mysql_1 ... done
    
  3. 查看运行日志:查看特定服务的日志docker-compose logs -f app

    # docker-compose logs -f
    Attaching to app_mysql_1, app_app_1
    app_1    | yarn install v1.22.17
    app_1    | [1/4] Resolving packages...
    app_1    | warning Resolution field "ansi-regex@5.0.1" is incompatible with requested version "ansi-regex@^2.0.0"
    app_1    | warning Resolution field "ansi-regex@5.0.1" is incompatible with requested version "ansi-regex@^3.0.0"
    app_1    | success Already up-to-date.
    app_1    | Done in 0.78s.
    app_1    | yarn run v1.22.17
    app_1    | $ nodemon src/index.js
    app_1    | [nodemon] 2.0.13
    app_1    | [nodemon] to restart at any time, enter `rs`
    app_1    | [nodemon] watching path(s): *.*
    app_1    | [nodemon] watching extensions: js,mjs,json
    app_1    | [nodemon] starting `node src/index.js`
    app_1    | Waiting for mysql:3306...........
    app_1    | Connected!
    app_1    | Connected to mysql db at host mysql
    app_1    | Listening on port 3000
    
  4. 删除所有的容器

    # docker-compose down
    Stopping app_mysql_1 ... done
    Stopping app_app_1   ... done
    Removing app_mysql_1 ... done
    Removing app_app_1   ... done
    Removing network app_default
    

8 创建image最佳实践

8.1 image层

  1. 查看image文件组成

    # docker image history getting-started
    IMAGE          CREATED        CREATED BY                                      SIZE      COMMENT
    77ca1987abde   10 days ago    /bin/sh -c #(nop)  CMD ["node" "src/index.js…   0B        
    947863fe4b66   10 days ago    /bin/sh -c yarn install --production            86.1MB    
    5738a14f4b25   10 days ago    /bin/sh -c #(nop) COPY dir:b43b032ba51228260…   4.6MB     
    0909fcbc4c2e   10 days ago    /bin/sh -c #(nop) WORKDIR /app                  0B        
    37afb0a6e721   10 days ago    /bin/sh -c apk add --no-cache python2 g++ ma…   223MB     
    1b156b4c3ee8   5 weeks ago    /bin/sh -c #(nop)  CMD ["node"]                 0B        
          5 weeks ago    /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B        
          5 weeks ago    /bin/sh -c #(nop) COPY file:4d192565a7220e13…   388B      
          5 weeks ago    /bin/sh -c apk add --no-cache --virtual .bui…   7.84MB    
          5 weeks ago    /bin/sh -c #(nop)  ENV YARN_VERSION=1.22.17     0B        
          5 weeks ago    /bin/sh -c addgroup -g 1000 node     && addu…   77.6MB    
          5 weeks ago    /bin/sh -c #(nop)  ENV NODE_VERSION=12.22.10    0B        
          3 months ago   /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B        
          3 months ago   /bin/sh -c #(nop) ADD file:9233f6f2237d79659…   5.59MB    
    
    • --no-trunc:查看完整输出内容

8.2 层缓存

  1. 当改变一个层,所有的下游层都必须要重建。可以重构Dockerfile以支持依赖的缓存。对于所有基于节点的应用, package.json定义了所有依赖,如果一开始复制了 package.json文件,安装依赖,再复制其他文件,然后只有当 package.json文件更改时才会重建yarn依赖。

  2. 查看我们所使用的Dockerfile

    FROM node:12-alpine
    RUN apk add --no-cache python2 g++ make
    WORKDIR /app
    COPY . .
    RUN yarn install --production
    CMD ["node", "src/index.js"]
                                 
    
  3. 修改Dockerfile内容:先复制package.json文件,再安装依赖,最后复制所有文件内容

    FROM node:12-alpine
    RUN apk add --no-cache python2 g++ make
    WORKDIR /app
    COPY package.json yarn.lock ./
    RUN yarn install --production
    COPY . .
    CMD ["node", "src/index.js"]
    
  4. 在Dockerfile文件同目录下创建 .dockerignore 文件,内容如下:

    node_modules
    
    • .dockerignore 文件是有选择的复制只与image相关的文件的一个简单方法。在本例中,node_modules文件夹会在第二次复制操作时被忽略,它可能会覆盖由RUN步骤中的命令创建的文件。
  5. 使用 docker build创建一个新镜像

    # docker build -t getting-started .   
    Sending build context to Docker daemon  4.656MB
    Step 1/7 : FROM node:12-alpine
     ---> 1b156b4c3ee8
    Step 2/7 : RUN apk add --no-cache python2 g++ make
     ---> Using cache
     ---> 37afb0a6e721
    Step 3/7 : WORKDIR /app
     ---> Using cache
     ---> 0909fcbc4c2e
    Step 4/7 : COPY package.json yarn.lock ./
     ---> 129fe0efb187
    Step 5/7 : COPY . .
     ---> 9d237c50ec6c
    Step 6/7 : RUN yarn install --production
     ---> Running in d1951023995a
    yarn install v1.22.17
    [1/4] Resolving packages...
    [2/4] Fetching packages...
    [3/4] Linking dependencies...
    [4/4] Building fresh packages...
    Done in 10.30s.
    Removing intermediate container d1951023995a
     ---> 9236fb3caf32
    Step 7/7 : CMD ["node", "src/index.js"]
     ---> Running in f4748415315d
    Removing intermediate container f4748415315d
     ---> 1b87ea345300
    Successfully built 1b87ea345300
    Successfully tagged getting-started:latest
    
  6. 任意修改 src/static/index.html 内容:如修改 </code>为"The Awesome Todo App"</p> </li> <li> <p>重新创建Docker image</p> <pre><code class="language-sh">#docker build -t getting-started . Sending build context to Docker daemon 4.656MB Step 1/7 : FROM node:12-alpine ---> 1b156b4c3ee8 Step 2/7 : RUN apk add --no-cache python2 g++ make ---> Using cache ---> 37afb0a6e721 Step 3/7 : WORKDIR /app ---> Using cache ---> 0909fcbc4c2e Step 4/7 : COPY package.json yarn.lock ./ ---> Using cache ---> 129fe0efb187 Step 5/7 : COPY . . ---> def0ab2c3473 Step 6/7 : RUN yarn install --production ---> Running in b371033126a4 yarn install v1.22.17 [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh packages... Done in 28.41s. Removing intermediate container b371033126a4 ---> 483d314e3860 Step 7/7 : CMD ["node", "src/index.js"] ---> Running in 6a2070d91e4b Removing intermediate container 6a2070d91e4b ---> 4c7cf643078a Successfully built 4c7cf643078a Successfully tagged getting-started:latest </code></pre> <ul> <li>可以看到 2-3 使用了cache</li> </ul> </li> </ol> </div> <!--conend--> <div class="p-2"></div> <div class="arcinfo my-3 fs-7 text-center"> <a href='/t/etagid107-0.html' class='tagbtn' target='_blank'>Linux</a><a href='/t/etagid301-0.html' class='tagbtn' target='_blank'>docker</a> </div> <div class="p-2"></div> </div> <div class="p-2"></div> <!--xg--> <div class="lbox p-4 shadow-sm rounded-3"> <div class="boxtitle"><h2 class="fs-4">相关</h2></div> <hr> <div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-566303.html">Arm64安装docker和docker-compose</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-566392.html">linux环境开机自启动nginx</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-566464.html">Linux获取栈空间大小</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-566165.html">Xlib Linux判断程序窗口是否为最小化</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-566414.html">安装指定版本docker</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-565602.html">Centos8 Docker部署ElasticSearch集群</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-565808.html">一步一步配置docker(tomcat+jenkins+phpmyadmin+nginx)</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-565165.html">linux下如何添加一个用户并且让用户获得root权限</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-565241.html">linux 恢复mysql 误删除数据</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-565160.html">linux 用时统计</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="">Linux磁盘操作:分区、格式化、挂载【转】</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div><div class="row g-0 py-2 border-bottom align-items-center"> <div class="col-7 col-lg-11 border-lg-end"> <h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-564591.html">Linux 上安装配置 VNC Server</a></h3> <div class="ltag fs-8 d-none d-lg-block"> </div> </div> </div> <!----> <!----> </div> <!--xgend--> </div> <div class="col-lg-3 col-12 p-0 ps-lg-2"> <!--box--> <!--boxend--> <!--<div class="p-2"></div>--> <!--box--> <div class="lbox p-4 shadow-sm rounded-3"> <div class="boxtitle pb-2"><h2 class="fs-4"><a href="#">标签</a></h2></div> <div class="clearfix"></div> <ul class="m-0 p-0 fs-7 r-tag"> </ul> <div class="clearfix"></div> </div> <!--box end--> </div> </div> </div> </main> <div class="p-2"></div> <footer> <div class="container-fluid p-0 bg-black"> <div class="container p-0 fs-8"> <p class="text-center m-0 py-2 text-white-50">一品网 <a class="text-white-50" href="https://beian.miit.gov.cn/" target="_blank">冀ICP备14022925号-6</a></p> </div> </div> <script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?6e3dd49b5f14d985cc4c6bdb9248f52b"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script> </footer> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.min.js"></script> </body> </html>