Docker 入门指南

Docker 入门指南

Docker Documentation | Docker Documentation

image-20220307090634652

0 Docker术语

0.1 容器(Container)

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

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

0.2 镜像(Image)

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

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

1 环境准备

1.0 安装 docker

# CentOS 下
cd /etc/yum.repos.d/
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce

# Ubuntu 下
sudo apt install docker.io

1.1 配置 docker 加速

vim  /etc/docker/daemon.json
{
    "registry-mirrors": [
        "https://1nj0zren.mirror.aliyuncs.com",
        "https://docker.mirrors.ustc.edu.cn",
        "http://f1361db2.m.daocloud.io",
        "https://registry.docker-cn.com"
    ]
}
systemctl daemon-reload 
systemctl restart docker

1.2 获取并安装 App

git clone https://github.com/docker/getting-started.git
cd /path/to/app
docker build -t getting-started .

1.3 启动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端口
  • -P - 将容器的端口暴露在宿主机的随机端口上
  • docker/getting-started - 要使用的镜像
  • --name - 指定名字
  • -t - 创建一个虚拟终端
  • -i - 将容器的标准输入保持打开
  • 退出 - exitCtrl + D

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行数据修改成以下内容
    // <p className="text-center">No items yet! Add one above!</p> 
    <p className="text-center">You have no todo items yet! Add one above!</p>
    
  2. 创建App更新后的image版本

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

    # 需要先删除旧版本的App容器
    # 停止App容器
    docker stop <the-container-id>
    # 删除App容器
    docker rm <the-container-id>
    # 一次命令停止并删除App容器
    docker rm -f <the-container-id>
    
    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 <container-id> cat /data.txt
    

    image-20220308090645544

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

    docker run -it ubuntu ls /
    

    image-20220308090443703

  4. 删除第一个容器

    docker rm -f <container-id>
    
  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 <container-id>
    
  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 <container-id>
    
  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 <container-id>
    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-container-id> 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:
    
  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 <CONTAINER-ID>
    
  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        
    <missing>      5 weeks ago    /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B        
    <missing>      5 weeks ago    /bin/sh -c #(nop) COPY file:4d192565a7220e13…   388B      
    <missing>      5 weeks ago    /bin/sh -c apk add --no-cache --virtual .bui…   7.84MB    
    <missing>      5 weeks ago    /bin/sh -c #(nop)  ENV YARN_VERSION=1.22.17     0B        
    <missing>      5 weeks ago    /bin/sh -c addgroup -g 1000 node     && addu…   77.6MB    
    <missing>      5 weeks ago    /bin/sh -c #(nop)  ENV NODE_VERSION=12.22.10    0B        
    <missing>      3 months ago   /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B        
    <missing>      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 内容:如修改 <title>为"The Awesome Todo App"

  7. 重新创建Docker image

    #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
    
    • 可以看到 2-3 使用了cache
posted @ 2022-03-20 11:01  f_carey  阅读(94)  评论(0编辑  收藏  举报