Skip to content

Docker 入门讲解

一. Docker 是什么?

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。 它让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到安装了任何 Linux 发行版本的机器上。

Docker 基于 LXC 来实现类似 VM 的功能,可以在更有限的硬件资源上提供给用户更多的计算资源。与同 VM 等虚拟化的方式不同,LXC 不属于全虚拟化、部分虚拟化或半虚拟化中的任何一个分类,而是一个操作系统级虚拟化。

Docker 是直接运行在宿主操作系统之上的一个容器,使用沙箱机制完全虚拟出一个完整的操作,容器之间不会有任何接口,从而让容器与宿主机之间、容器与容器之间隔离的更加彻底。每个容器会有自己的权限管理,独立的网络与存储栈,及自己的资源管理能,使同一台宿主机上可以友好的共存多个容器。

Docker 借助 Linux 的内核特性,如:控制组(Control Group)、命名空间(Namespace)等,并直接调用操作系统的系统调用接口。从而降低每个容器的系统开销,并实现降低容器复杂度、启动快、资源占用小等特征。

Docker 使用客户端-服务器 (C/S) 架构模式,使用远程 API 来管理和创建 Docker 容器。

Docker 容器通过 Docker 镜像来创建。

容器与镜像的关系类似于面向对象编程中的对象与类。

二. Docker 的特点及应用场景

优点:

  • Docker 使您能够将应用程序与基础架构分开,从而可以快速交付软件。借助 Docker,您可以与管理应用程序相同的方式来管理基础架构。通过利用 Docker 的方法来快速交付,测试和部署代码,您可以大大减少编写代码和在生产环境中运行代码之间的延迟。

应用场景

  • Web 应用的自动化打包和发布。
  • 自动化测试和持续集成、发布。
  • 在服务型环境中部署和调整数据库或其他的后台应用。
  • 从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。

三. Docker 三大概念

TIP

镜像(Image)、容器(Container)、仓库(Repository)

  • 镜像(Image)

  • 镜像,就是像是我们装机时候需要的系统盘或者系统镜像文件,这里它负责创建 docker 容器,有很多官方现成的镜像:node、mysql、monogo、nginx 可以从远程仓库下载

镜像是创建 docker 容器的基础,docker 镜像类似于虚拟机镜像,可以将它理解为一个面向 docker 引擎的只读模块,包含文件系统。

  • 2、容器(Container)

  • 可以比拟成一个迷你的系统,例如:一个只安装了 mysql5.7 的 linux 最小系统,当然你喜欢也可以把 mysqlnode 安装在同一个容器中,记住:容器与容器,容器和主机都是互相隔离的

  • 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。基于 docker 镜像,我们可以创建许许多多的容器出来。容器可以被创建、启动、停止、删除、暂停等。

  • 镜像自身是只读的,容器从镜像启动的时候,docker 会在镜像的最上层创建一个可写文件层,镜像本身保持不变。

  • 3、仓库(Repository)

  • 仓库就像是 github 那样的,我们可以制作镜像然后 push 提交到云端的仓库,也可以从仓库 pull 下载镜像

四. Docker 的安装及镜像加速

1. 各种版本 Docker 安装

windows Docker 安装教程https://www.runoob.com/docker/windows-docker-install.htmlUbuntu Docker 安装教程https://www.runoob.com/docker/ubuntu-docker-install.htmlCentOS Docker 安装教程https://www.runoob.com/docker/centos-docker-install.htmlMacOS Docker 安装教程https://www.runoob.com/docker/macos-docker-install.html

2. docker 镜像加速

Docker 镜像加速教程https://www.runoob.com/docker/docker-mirror-acceleration.html

国内从 DockerHub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。Docker 官方和国内很多云服务商都提供了国内加速器服务,例如:

  • 科大镜像:https://docker.mirrors.ustc.edu.cn/
  • 网易:https://hub-mirror.c.163.com/
  • 阿里云:https://<你的 ID>.mirror.aliyuncs.com
  • 七牛云加速器:https://reg-mirror.qiniu.com

当配置某一个加速器地址之后,若发现拉取不到镜像,请切换到另一个加速器地址。国内各大云服务商均提供了 Docker 镜像加速服务,建议根据运行 Docker 的云平台选择对应的镜像加速服务。

(1) Ubuntu16.04+、Debian8+、CentOS7 配置 对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容(如果文件或文件夹不存在请新建该文件):

json
{
  "registry-mirrors": ["https://reg-mirror.qiniu.com/"]
}

之后重新启动服务:

sh
sudo systemctl daemon-reload
sudo systemctl restart docker

(2) wondows 配置

例如: windows 安装号 docker 后,点击 image.png启动 docker -> setting -> Docker Engine,在右侧输入栏编辑 json 文件。 找到 json 中registry-mirrors节点或添加该节点,值为数组[],将https://hub-mirror.c.163.com 加到"registry-mirrors"的数组里,点击 Apply & Restart按钮,等待 Docker 重启并应用配置的镜像加速器。

image.png

json
{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "features": {
    "buildkit": true
  },
  "registry-mirrors": ["https://hub-mirror.c.163.com"]
}

3. 检查加速器是否生效

在命令行执行 docker info,如果从结果中包含如下内容,说明配置成功。 image.png

4. docker Hello Word

当以上步骤都安装并配置好加速器后,可以运行你的第一个 hello word 了

Docker 允许你在容器内运行应用程序, 使用 docker run 命令来在容器内运行一个应用程序。 输出 Hello world

打开命令行窗口,执行命令docker run ubuntu:15.10 /bin/echo "Hello world"; 注意: 若本地没有ubuntu:15.10这个镜像,Dokcer 会从远程仓库拉取镜像,当拉取镜像成功后,才会输出hello wordimage.png

image.png

各个参数解析:

  • docker: Docker 的二进制执行文件。
  • run: 与前面的 docker 组合来运行一个容器。
  • ubuntu:15.10 :指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
  • /bin/echo "Hello world": 在启动的容器里执行的命令

以上命令完整的意思可以解释为:Docker 以 ubuntu15.10 镜像创建一个新容器,然后在容器里执行 bin/echo "Hello world",然后输出结果。

五. Docker 容器的详细使用

1. 获取镜像docker pull

如果我们本地没有 ubuntu 镜像,我们可以使用 docker pull 命令来载入 ubuntu 镜像:

sh
docker pull ubuntu

注意: 若是 pull 时候不备注镜像的版本,则默认 pull 下来的是最新的版本latest

2. 运行容器docker run

docker run 命令可以下载镜像 ->通过镜像创建容器 ->启动运行容器

2.1 解析命令

sh
# 运行创建docker容器:承载 vue2+webpack+nodejs10
# docker run -it -d --name myvue2 --privileged -p 8081:8080 -v  /Users/eric/my-repository/my-app-vue2:/app/vue node:10.16.2 /bin/bash -c "cd /app/vue && node -v && npm install && npm run serve"
参数描述
-d以守护进程的方式让容器在后台运行,在这您之 前可能使用的是 pm2 来守护进程
-it这里是 -i 和 -t 的缩写**-i:告诉 Docker 容器保持标准输入流对容器开放,即使容器没有终端连接****-t:告诉 Docker 为容器分配一个虚拟终端**
--name myvue2将容器命名为 myvue2,这样访问和操作容 器等就不需要输入一大串的容器 ID
--privileged让容器的用户在容器内能获取完全 root 权限
-p 8081:8080将容器的 8080 端口映射到宿主机的 8081 端口上这样我们访问本机的 localhost:8081,就是访问到容器的 8080 端口因为容器都是独立运行互相隔离的,容器与容器各自的 8080 端口、容器跟主机各自的8080 端口都不是一个东西,主机只有在这给端口做映射才能访问到容器端口
-v /Users/eric/my-repository/my-app-vue2:/app/vue将主机的 my-app-vue2 目录(命令行这里只能写绝对路径哈)下的内容挂载到容器的目录/app/vue 内,如果容器的指定目录有文件/文件夹,将被清空挂载后,容器修改 /app/vue 目录的内容,也是在修改主机目录/Users/eric/my-repository/my-app-vue2 内容
node:10.16.2这里是指定 nodejs,版本为 10.16.2 的镜像来创建容器如果不指定版本,会默认下载当前镜像的最新版本
/bin/bash -c "cd /app/vue2 && node -v && npm install && npm run serve"/bin/bash:是在让容器分配的虚拟终端以 bash 模式执行命令-c ""cd /app/vue2 && node -v && npm install && npm run serve:只能执行一条 shell 命令,需要多个命令按需用&&、

2.2 其他方式 也可以利用docker create命令创建一个容器,创建后的的容器处于停止状态,可以使用 docker start 命令来启动它。也可以运行docker run命令来直接从镜像启动运行一个容器。

docker run = docker create + docker start

2.3 详细介绍

当利用 docker run 创建并启动一个容器时,docker 在后台的标准操作包括:

(1)检查本地是否存在指定的镜像,不存在就从公有仓库下载。

(2)利用镜像创建并启动一个容器。

(3)分配一个文件系统,并在只读的镜像层外面挂载一层可读写层。

(4)从宿主机配置的网桥接口中桥接一个虚拟的接口到容器中。

(5)从地址池中配置一个IP地址给容器。

(6)执行用户指定的应用程序。

(7)执行完毕后容器终止。

当我们启动一个容器时,首先需要确定这个容器是运行在前台还是运行在后台。

a. 前台模式

在前台模式下(不指定-d参数即可),Docker 会在容器中启动进程,同时将当前的命令行窗口附着到容器的标准输入、标准输出和标准错误中。 也就是说容器中所有的输出都可以在当前窗口中看到。甚至它都可以虚拟出一个 TTY 窗口,来执行信号中断。

sh
#  例如
$ docker run -it ubuntu /bin/bash

这一切都是可以配置的:

参数说明默认值
-a, --attach value挂载上标准输入(STDIN)、输出(STDOUT)或输出错误(STDERR)默认为空
-t, --tty在新容器内指定一个伪终端或终端
--sig-proxy代理接收到进程的信号 值:true/falsetrue
-i, --interactive允许你对容器内的标准输入 (STDIN) 进行交互

如果在执行docker run命令时没有指定-a参数,那么 Docker 默认会挂载所有标准数据流,包括输入输出和错误,你可以单独指定挂载哪个标准流。例如命令:docker run -a stdin -a stdout -i -t ubuntu /bin/bash

如果要进行交互式操作(例如 Shell 脚本),那我们必须使用-i -t参数同容器进行数据交互。但是当通过管道同容器进行交互时,就不需要使用-t 参数,例如命令:echo test | docker run -i busybox cat

b. 后台模式 -d

如果在docker run后面追加-d=true或者-d参数,那么容器将会运行在后台模式。 此时所有I/O数据只能通过网络资源或者共享卷组来进行交互。因为容器不再监听你执行docker run的这个终端命令行窗口。 但你可以通过执行docker attach来重新附着到该容器的会话中。

参数:-d, --detach

在大部分的场景下,我们希望 docker 的服务是在后台运行的,我们可以过 -d 指定容器的运行模式。需要注意的是,容器运行在后台模式下,是不能使用--rm选项的。

例如,我们对上面的 hello word 来一次后台运行,只需要加上-d参数即可:

sh
docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"

# 输出
# 08282ac73c066295b392a06c233dc1076c38d98c05828be6635644b716e190cf

如图: image.png

如上图,以后台模式启动容器,在输出中,我们没有看到期望的 "Hello world",而是一串长字符,这串字符称为容器 ID, 对每个容器来说都是唯一的,我们可以通过容器 ID 来查看对应的容器发生了什么。

首先,我们需要确认容器有在运行,可以通过 docker ps 来查看: image.png

字段解释:

字段说明其他
CONTAINER ID容器 ID
IMAGE使用的镜像
COMMAND启动容器时运行的命令
CREATED容器的创建时间
STATUS容器状态(7 种)created(已创建),restarting(重启中),running 或 Up(运行中),removing(迁移中),paused(暂停),exited(停止),dead(死亡)
PORTS容器的端口信息和使用的连接类型(tcp\udp)
NAMES自动分配的容器名称

3. 启动/停止容器docker start/stop

我们使用 docker start/stop <ID或name> 命令来启动/停止容器:

sh
# 启动
docker start [container_name/container_id]

# 停止
docker stop [container_name/container_id]

image.png

可以看到,容器已经被停止了

4. 重启容器docker start

使用场景实例:

  • 在加入新的 npm 包依赖需要重新编译的时候使用重启运行编译
sh
docker restart [container_name/container_id]

5. 删除容器docker rm

删除容器使用 docker rm 命令:

在容器停止的状态才能删

sh
docker rm -f 1e560fca3906

6. 清理掉所有处于终止状态的容器

sh
docker container prune

7. 查看容器docker ps

sh
# 查看所有的容器(包括已停止的)
docker ps -a    # -a 参数即 all,查看所有(包括已停止的),可以查看容器ID、基础镜像、容器名称、运行状态、端口映射等

# 查看运行中的容器
$ docker ps # 默认是查看运行中的,可以查看容器ID、基础镜像、容器名称、运行状态、端口映射等

# 查看容器的信息,例如端口号的映射、目录挂载
docker inspect [images_name/images_id]

# 创建容器后,有时候需要看一下容器资源占用
docker stats <ID>

8. 进入/退出 容器docker attach/exec

在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:

ps: 有些容器没有 bash,需要改成/bin/sh,例如 mysq、mongodb 的

sh
docker attach -it [container_name/container_id] /bin/bash # 方式1:进入运行中的容器
docker exec -it [container_name/container_id] /bin/bash  # 方式2:(推荐),用该命令进入容器,exit退出时,不会导致容器的停止。

# 例如:
docker exec -it 12f9a9378ebe /bin/bash  # 其中12f9a9378ebe是容器ID

exit # 退出容器

注意:

  • docker attach进入,exit 退出会导致容器停止运行,请改用docker exec <ID>命令进入容器,再用exit退出
  • docker attach进入,exit 退出会导致容器停止运行,请改用docker exec <ID>命令进入容器,再用exit退出
  • docker attach进入,exit 退出会导致容器停止运行,请改用docker exec <ID>命令进入容器,再用exit退出

Bad 示例: image.png

Good 示例:

10. 查看容器日志docker logs <ID>

在宿主主机内使用 docker logs <ID>命令,查看容器内的标准输出:

sh
docker logs 08282ac73c06

# 查看实时日志,不会退出终端,加上-f参数即可
docker logs -f 08282ac73c06

image.png

11. 导出和导入容器

导出容器

如果要导出本地某个容器,可以使用 docker export 命令。

sh
docker export 1e560fca3906 > ubuntu.tar

含义:导出容器 1e560fca3906 快照到本地文件 ubuntu.tar。 1 这样将导出容器快照到本地文件。

导入容器快照

可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1

sh
cat docker/ubuntu.tar | docker import - test/ubuntu:v1

2

此外,也可以通过指定 URL 或者某个目录来导入,例如:

sh
docker import http://example.com/exampleimage.tgz example/imagerepo

12. 网络端口映射

docker 容器在启动的时候,如果不指定端口映射参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。 端口映射通过-P-p参数来实现

1、-P: (大写)将容器内部开放的网络端口随机映射到宿主机的一个端口上 2、-p: (小写)指定要映射的端口,一个指定端口上只可以绑定一个容器;

支持的格式如下:

IP:HOSTPORT:CONTAINERPORT:指定 ip、指定宿主机 port、指定容器 port

  • 适用于映射到指定地址的指定端口

例如:将容器的 5000 端口映射到指定地址 127.0.0.1 的 5000 端口上:

sh
docker run -it -d -p 127.0.0.1:5000:5000 docker.io/centos:latest /bin/bash

image.png

IP::CONTAINERPORT:指定 ip、未指定宿主机 port(随机)、指定容器 port

  • 适用于映射到指定地址的任意端口

例如:将容器的 4000 端口映射到 127.0.0.1 的任意端口上:

sh
docker run -it -d -p 127.0.0.1::4000 docker.io/centos:latest /bin/bash

image.png 注:会将容器的 ip127.0.0.1 和 4000 端口,随机映射到宿主机的一个端口上。

HOSTPORT:CONTAINERPORT :未指定 ip、指定宿主机 port、指定容器 port

  • 适用于将容器指定端口指定映射到宿主机的一个端口上(映射所有接口地址)

例如:将容器的 80 端口映射到宿主机的 8000 端口上:

sh
docker run -itd -p 8000:80 docker.io/centos:latest /bin/bash

image.png 注:上边的操作默认会绑定本地所有接口上的所有地址。

映射访问示例 image.png

将容器的 80 端口映射到宿主机的 8000 端口上,并在容器中安装 httpd 服务,而后在宿主机上访问 http://IP:HOSTPORT,即访问http://192.168.101.222:8000/,结果如下:image.png

13. 查看映射端口配置

通过 docker ps 命令可以查看到容器的端口映射,docker 还提供了另一个快捷方式 docker port,使用 docker port 可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。

例如

sh
# runoob@runoob:~#  docker ps
# CONTAINER ID        IMAGE                             PORTS                     NAMES
# bf08b7f2cd89        training/webapp     ...        0.0.0.0:5000->5000/tcp    wizardly_chandrasekhar
# d3d5e39ed9d3        training/webapp     ...        0.0.0.0:32769->5000/tcp   xenodochial_hoov

或者

sh
runoob@runoob:~$ docker port bf08b7f2cd89
5000/tcp -> 0.0.0.0:5000

14. 容器主机文件拷

sh
# 将容器文件拷贝到主机
docker cp [container_id/container_name] : [文件目录] [主机目录]

# 将主机的目录拷贝到容器
docker cp [主机目录] [container_id/container_name] : [文件目录]

六. 镜像的详细使用

当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。

1. 列出 local 镜像列表docker images

我们可以使用 docker images 来列出本地主机上的镜像。

image.png

sh
docker images

各个选项说明:

  • REPOSITORY:表示镜像的仓库源 TAG:镜像的标签(或版本) IMAGE ID:镜像 ID CREATED:镜像创建时间 SIZE:镜像大小

同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如 ubuntu 仓库源里,有 15.10、14.04 等多个不同的版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。默认为latest(最新版本) 如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像。

例如:如果要使用版本为 14.04 的 ubuntu 系统镜像来运行容器时,命令如下

sh
docker run -t -i ubuntu:14.04 /bin/bash

我们可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为: https://hub.docker.com/ 我们也可以使用 docker search 命令来搜索镜像。

比如我们需要一个 httpd 的镜像来作为我们的 web 服务。我们可以通过 docker search 命令搜索 httpd 来寻找适合我们的镜像。

sh
docker search httpd

image.png NAME: 镜像仓库源的名称 DESCRIPTION: 镜像的描述 OFFICIAL: 是否 docker 官方发布 stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。 AUTOMATED: 自动构建。

3. 删除镜像docker rmi

镜像删除使用 docker rmi 命令,比如我们删除 hello-world 镜像:

需要先删除以此镜像为基础的容器

sh
docker rmi hello-world

3

4. 获取一个新的镜像

当我们在本地主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。如果我们想预先下载这个镜像,我们可以使用 docker pull 命令来下载它。 具体的拉取命令可以在镜像仓库上去复制

sh
# 下载镜像(:指定版本)
docker pull [images_name:tag]

# 下载镜像(最新版本(默认))
docker pull [images_name]

下载完成后,我们可以直接使用这个镜像来运行容器。

5. 查看镜像的构建历史

sh
docker history [images_name]

6. 创建镜像

创建镜像有两种方法: (1) 基于已有镜像的容器创建(更新镜像)。主要是利用 docker commit 命令。(不推荐) (2) 基于dockerfile创建,主要用docker build命令。(推荐)

理解 dockerCommit.png

6.1. 基于已有镜像的容器创建(不推荐)

命令格式:

sh
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

例如: 我们的目标是:通过基础镜像 centos:7,在该镜像中安装 jdk 和 tomcat 以后将其制作为一个新的镜像 mycentos:7。

1、创建容器

sh
 # 拉取镜像
 docker pull centos:7
# 创建容器
docker run -di --name centos7 centos:7

2、拷贝资源

sh
 # 将宿主机的 jdk 和 tomcat 拷贝至容器
docker cp jdk-11.0.6_linux-x64_bin.tar.gz centos7:/root docker cp apache-tomcat-9.0.37.tar.gz centos7:/root

3、安装资源

sh
 # 进入容器
docker exec -it centos7 /bin/bash

# ----------------------以下操作都在容器内部执行----------------------
# 切换至 /root 目录
cd root/
# 创建 java 和 tomcat 目录
mkdir -p /usr/local/java mkdir -p /usr/local/tomcat
# 将 jdk 和 tomcat 解压至容器 /usr/local/java 和 /usr/local/tomcat 目录中
tar -zxvf jdk-11.0.6_linux-x64_bin.tar.gz -C /usr/local/java/ tar -zxvf apache-tomcat-9.0.37.tar.gz -C /usr/local/tomcat/
# 配置 jdk 环境变量
vi /etc/profile
# 在环境变量文件中添加以下内容
export JAVA_HOME=/usr/local/java/jdk-11.0.6/ export PATH=$PATH:$JAVA_HOME/bin
# 重新加载环境变量文件
source /etc/profile
 # 测试环境变量是否配置成功
java -version java version "11.0.6" 2020-01-14 LTS Java(TM) SE Runtime Environment 18.9 (build 11.0.6+8-LTS) Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.6+8-LTS, mixed mode)
# 删除容器内
jdk tomcat rm jdk-11.0.6_linux-x64_bin.tar.gz apache-tomcat-9.0.37.tar.gz -rf

4、构建镜像

sh
docker commit -a="mrhelloworld" -m="jdk11 and tomcat9" centos7 mycentos:7
  • -a:提交的镜像作者;
  • -c:使用 Dockerfile 指令来创建镜像;
  • -m:提交时的说明文字;
  • -p:在 commit 时,将容器暂停。

5、使用构建的镜像创建容器

sh
 # 创建容器
docker run -di --name mycentos7 -p 8080:8080 mycentos:7
# 进入容器
docker exec -it mycentos7 /bin/bash
# 重新加载配置文件
source /etc/profile
# 测试 java 环境变量
[root@dcae87df010b /]# java -version java version "11.0.6" 2020-01-14 LTS Java(TM) SE Runtime Environment 18.9 (build 11.0.6+8-LTS) Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.6+8-LTS, mixed mode)
# 启动 tomcat
/usr/local/apache-tomcat-9.0.37/bin/startup.sh
# 访问 http://192.168.10.10:8080/ 看到页面说明环境 OK!

6.2. 基于 Dockerfile 创建(推荐)

Dockerfile 是由多行命令语句组成的,并且在文件中支持以 # 开始的注释行。我们一般将 Dockerfile 文件分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。

Dockerfile 文件的名字就是Dockerfile,固定写法

Dockerfile 文件基本结构

sh
# 1、第一行必须是 FROM 基础镜像信息
FROM ubuntu

# 2、维护者信息
LABEL MAINTAINER=xxxxx@qq.com

# 3、镜像操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

# 4、容器启动执行指令
CMD /usr/sbin/nginx

配置参数说明:

参数说明备注
FROMFROM 是构建镜像的基础源镜像,该 Image 文件继承官方的 node image。详细说明:Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令! 它引入一个镜像作为我们要构建镜像的基础层,就好像我们首先要安装好操作系统,才可以在操作系统上面安装软件一样。
RUN后面跟的是在容器中要执行的命令,等同于,在终端操作的 shell 命令详细说明:每一个 RUN 指令都会新建立一层,在其上执行这些命令,我们频繁使用 RUN 指令会创建大量镜像层,然而 Union FS 是有最大层数限制的,不能超过 127 层,而且我们应该把每一层中我用文件清除,比如一些没用的依赖,来防止镜像臃肿。
WORKDIR容器的工作目录
COPY拷贝文件至容器的工作目录下,.dockerignore 指定的文件不会拷贝
EXPOSE将容器内的某个端口导出供外部访问
CMDDockerfile 执行写一个 CMD 否则后面的会被覆盖,CMD 后面的命令是容器每次启动执行的命令,多个命令之间可以使用 && 链接,例如 CMD git pull && npm start详细说明:CMD 指令用来在启动容器的时候,指定默认的容器主进程的启动命令和参数。 它有两种形式:CMD echo 1 CMD ["npm", "run", "test"] 必须是双引号第一种执行的命令会被包装成:++CMD [ "sh", "-c", "echo 1" ]++ JSON 数组形式,一般推荐 JSON 数组形式。容器中的应用都应该以前台执行,而不是启动后台服务,容器内没有后台服务的概念。对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义。比如 CMD service nginx start 它等同于 CMD [ "sh", "-c", "service nginx start"] 主进程实际上是 sh,sh 也就结束了,sh 作为主进程退出了。
ENVENV 指令用来设置环境变量它有两种形式ENV \<key> \<value> ENV \<key1>=\<value1> \<key2>=\<value2>... 定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

Dockerfile 文件中 Run 命令和 CMD 命令的区别:

  • RUN:是图像构建步骤,RUN 命令之后的容器状态将被提交到 docker 镜像. Dockerfile 可以有许多 RUN 步骤,它们相互叠加以构建图像.
  • CMD:是启动构建映像时默认情况下容器执行的命令. Dockerfile 只能有一个 CMD.使用 docker run $image $other_command 启动容器时,可以覆盖 CMD. 参考:https://blog.csdn.net/m0_45406092/article/details/103939810

Dockerfile 文件位置:

  • 一般应该会将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个 .dockerignore

用 Dockerfile 创建镜像步骤

1、根据以上内容编写 Dockerfile 文件 2、创建镜像 有了 Dockerfil 之后,在 Dockerfile 所在目录执行命令:

sh
docker build -t `<image_name>` .

build 命令用来制作镜像, -t 是给镜像打标签(命名), -f 参数是指定 Dockerfile 路径,由于我们使用的是默认 Dockerfile 名称,所以可以不同填写该参数。 最后一个.也不要省略,表示 Dockerfile 文件的所在目录, 代表是当前路径,它指定镜像构建的上下文。

真正制作镜像的是 docker server,当我们执行 build 命令时,docker client 会将上下文路径下的所有内容打包,然后上传给 docker server。这样当我们要在 Dockerfile 文件中执行 如 COPY 指令,就可以将上下文中的文件复制到镜像中去了。

镜像构建完成后,可以通过 docker images 来列出所有的镜像

3、接着可以创建一个容器并运行

提示

shell 脚本太长的时候我们可以用 \把一行命令分成多行

例如:

sh
docker run \
-it \
-d \
--name myvue2 \
--privileged \
-p 8081:8080 \
-v /Users/eric/my-repository/my-app-vue2:/app/vue \
node:10.16.2 \
/bin/bash -c "cd /app/vue2 && node -v && npm install && npm run serve"

以上都完成后,在宿主机中可以使用 curl 测试服务器提供的服务是否正常

sh
curl localhost:3000

7. 本地 Docker 镜像推送到 Docker Hub 仓库

build好镜像后,镜像已经存在了我们本机硬盘,那我们实际中要怎么以仓库的方式上传到服务器呢?这里通常有 2 个方法。

  • 一是自己搭建镜像仓库比如(harbor),还有就是官方的 docke hub,类似 gitlab。
  • 二是以 docker hub,首先需要注册 docker hub 账号,官网注册地址。然后登陆。

(1)命令登录 docker

sh
docker login

image.png

提示:Login Succeeded 表示登录成功。

(2)登录成功后,给要 push 到仓库的镜像添加 tag,再 push

注意:

  • 添加 tag 时必须在前面加上自己的 dockerhub 的 username,例如:xiaoli123fendou/xxxxx,否则 push 时候会报错
  • 添加 tag 时必须在前面加上自己的 dockerhub 的 username,例如:xiaoli123fendou/xxxxx,否则 push 时候会报错
  • 添加 tag 时必须在前面加上自己的 dockerhub 的 username,例如:xiaoli123fendou/xxxxx,否则 push 时候会报错

添加 tag

sh
docker tag 镜像名 username/仓库名[tagName]
# 例如:docker tag express-docker-demo xiaoli123fendou/express-docker-demo
# tagName选填,不填默认latest

接着 push 到 daocker Hub

sh
docker push `<标签名>`
# 例如: docker push xiaoli123fendou/express-docker-demo

image.png

注意: 若 push 时候报错 “denied: requested access to the resource is denied” 则是因为添加 tag 或者创建镜像时候的 tag 名没以 docker Hub 的 username 开头所致 例如,错误示例: image.png

(3)在 docke hub 查看刚刚 push 的镜像 登录docker Hub,查看刚刚 push 的镜像 image.png 可以看到这个镜像是 public 的,任何人都可以 pull 使用,可以在 setting 中设置为私有的

(4)镜像已经 push 到了 docker Hub 里面,实际中若要使用,可以通过 docker Hub 提供的 pull 命令 pull 使用 image.png

8. 本地 Docker 镜像离线迁移

说明:

  • 以上通过 push 本地构建的镜像到 docker Hub 的,再在服务器通过 pull 的来拉取镜像部署项目的方式,对于一些内网的服务器来说行不通,除非自己手动搭建仓库,一般公司的服务都处于内网隔离状态,因此上面的方式一般只用于自己的服务器,要想通过离线的方式来拷贝 images,可以看一下下面的方法,或许很有帮助

实现方式:用docker savedocker load命令来存储和载入镜像

8.1 保存 docker 镜像为tar文件

命令

sh
# 格式:docker save -o <要保存的文件名> <要保存的镜像>

# 例如
docker save -o express-docker-demo.tar xiaoli123fendou/express-docker-demo:0.0.1

注意:

  • a)保存镜像为 tar 文件时,格式应该给上:用户名/镜像名
  • b)tar 文件的保存位置应该是执行当前命令的所在目录
  • c)你也可以显示的指向路径如:express-demo/express-docker-demo.tar ,表示将 express-docker-demo.tar 文件保存在 express-demo 目录下(指定的目录必须先存在,否则会保存失败)

然后,就可以将保存得到的镜像 tar 文件通过 U 盘或传输工具(xftp 等)传输到目标服务器,通过 docker load 加载得到目标服务器本地镜像

8.2 加载 tar 文件得到镜像

命令

sh
docker load --input `<文件名>`

docker load -i  `<文件名>`

docker load > `<文件名>`

# 例如:
docker load -i express-docker-demo

docker load > express-docker-demo

其中: -i (--input) : 指定文件

加载 tar 文件时,可以指定 tar 文件的路径,如 docker load -i /home/file/express-docker-demo.tar

9. 构建一个含有多个软件环境的镜像

如果一个镜像中同时要安装多个软件,如:Nginx,mysql,redis,这时我们有两种方式 (方式一)直接在一个已经有这些软件环境的镜像的基础上来构建我们的镜像 (方式二)直接在构建镜像时,通过命令,现安装各种需要的软件 例如:方式二可能会有这样一个 Dockerfile 文件

Dockerfile
FROM centos:centos7
MAINTAINER ztd "770960546@qq.com"
# 准备工作创建文件夹
RUN \
mkdir -p /opt/tools \
&& mkdir -p /etc/redis \
&& mkdir /opt/logs \
&& mkdir -p /data/mysql
# 复制文件
COPY softwares/jdk-8u102-linux-x64.tar.gz /opt/tools
COPY softwares/redis-3.2.8.tar.gz /opt/tools
COPY softwares/apache-tomcat-7.0.70.tar.gz /opt/tools
COPY redis.conf /etc/redis/redis.conf
COPY supervisord.conf /etc/supervisord.conf
COPY program.conf /etc/program.conf
# 复制数据库文件
COPY softwares/libaio-0.3.107-10.el6.x86_64.rpm /opt/tools
COPY softwares/MySQL-client-5.6.23-1.rhel5.x86_64.rpm /opt/tools
COPY softwares/MySQL-devel-5.6.23-1.rhel5.x86_64.rpm /opt/tools
COPY softwares/MySQL-server-5.6.23-1.rhel5.x86_64.rpm /opt/tools
# 复制nginx安装文件
COPY softwares/nginx-1.13.7.tar.gz /opt/tools
#COPY nginx.conf /opt/tools/nginx.conf
# 安装 sshd 修改密码
RUN \
yum install passwd openssl openssh-server -y \
&& ssh-keygen -q -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key -N '' \
&& ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N '' \
&& ssh-keygen -t dsa -f /etc/ssh/ssh_host_ed25519_key -N '' \
&& sed -i "s/#UsePrivilegeSeparation.*/UsePrivilegeSeparation no/g" /etc/ssh/sshd_config \
&& sed -i "s/UsePAM.*/UsePAM no/g" /etc/ssh/sshd_config \
&& echo 123456 | passwd --stdin root \
&& echo root: 123456|chpasswd \
&& rm -rf /var/cache/yum/*
# 安装redis
RUN \
yum install gcc -y \
&& cd /opt/tools \
&& tar -xzf redis-3.2.8.tar.gz \
&& rm -rf redis-3.2.8.tar.gz \
&& cd redis-3.2.8 && yum -y install tcl && make && make install \
&& cd /opt/tools \
&& rm -rf redis-3.2.8 \
&& rm -rf /var/cache/yum/*
# 安装mysql
RUN \
yum -y install perl perl-devel perl-Module-Install.noarch net-tools \
&& cd /opt/tools \
&& rpm -ivh libaio-0.3.107-10.el6.x86_64.rpm \
&& rpm -ivh MySQL-server-5.6.23-1.rhel5.x86_64.rpm \
&& rpm -ivh MySQL-client-5.6.23-1.rhel5.x86_64.rpm \
&& rpm -ivh MySQL-devel-5.6.23-1.rhel5.x86_64.rpm \
&& chown -R mysql:mysql /data/mysql \
&& /etc/init.d/mysql start \
&& mysqltmppwd=`cat /root/.mysql_secret | cut -b 87-102` \
&& mysqladmin -u root -p${mysqltmppwd} password "123456" \
&& mysql -uroot -p123456 -e"grant all privileges on *.* to root@'%' identified by '123456' with grant option" \
&& mysql -uroot -p123456 -e"flush privileges" \
&& /etc/init.d/mysql stop \
&& rm -rf libaio-0.3.107-10.el6.x86_64.rpm \
&& rm -rf MySQL-client-5.6.23-1.rhel5.x86_64.rpm \
&& rm -rf MySQL-devel-5.6.23-1.rhel5.x86_64.rpm \
&& rm -rf MySQL-server-5.6.23-1.rhel5.x86_64.rpm \
&& rm -rf /var/cache/yum/* \
&& sed -i -e "10a datadir = /data/mysql" /usr/my.cnf
# 安装 nginx
RUN \
yum -y install gcc-c++ zlib zlib-devel openssl openssl--devel pcre pcre-devel \
&& cd /opt/tools \
&& tar -zxv -f nginx-1.13.7.tar.gz \
&& rm -rf nginx-1.13.7.tar.gz \
&& cd nginx-1.13.7 \
&& ./configure --with-http_stub_status_module \
&& make && make install \
&& cd .. \
&& rm -rf nginx-1.13.7 \
&& rm -rf /var/cache/yum/*
# && echo "daemon off" >> /usr/local/nginx/conf/nginx.conf
# && cp -rf /opt/tools/nginx.conf /usr/local/nginx/conf/nginx.conf
# 安装supervisor
RUN \
yum -y install python-setuptools \
&& easy_install supervisor \
&& rm -rdf /var/cache/yum/*
# 设置java环境变量
RUN \
cd /opt/tools \
&& tar -zxvf jdk-8u102-linux-x64.tar.gz \
&& rm -rf jdk-8u102-linux-x64.tar.gz \
&& tar -zxvf apache-tomcat-7.0.70.tar.gz \
&& rm -rf apache-tomcat-7.0.70.tar.gz \
&& echo 'export JAVA_HOME=/opt/tools/jdk1.8.0_102' >> /etc/profile \
&& echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile \
&& echo 'export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar' >> /etc/profile \
&& source /etc/profile
# 设置环境变量
EXPOSE 22 80 3306 6379
CMD /usr/bin/supervisord -c /etc/supervisord.conf
#CMD /usr/sbin/init
#  dockerc 常用命令
#查看当前docker版本
docker -v
#查看当前本地所有镜像
docker images
#构造镜像,用法docker build -t 镜像名称 .
docker build -t docker_demo .
#用于容器与主机之间的数据拷贝。用法docker cp 主机文件地址 容器内地址。12d7f14v45cv为容器id。
docker cp /www/runoob 12d7f14v45cv:/www/
#创建一个新的容器并运行,-d为后台执行,-p 9000:3000前面为主机端口,后面是容器端口。docker_demo镜像名
docker run -d -p 9000:3000 docker_demo
#启动已被停止的容器
docker start docker_demo
#关闭已被启动的容器
docker stop docker_demo
#重新启动容器
docker restart docker_demo
#杀掉一个运行中的容器。
docker kill -s KILL docker_demo
#删除一个或多个容器。-f :通过SIGKILL信号强制删除一个运行中的容器-l :移除容器间的网络连接,而非容器本身-v :-v 删除与容器关联的卷
docker rm -f docker_demo、docker_demo1
#在运行的容器中执行命令。104e28f2f072容器id
sudo docker exec -it 104e28f2f072 /bin/bash
#列出容器。 -a:所有容器包含没有运行的
docker ps
#获取容器获取容器的日志 104e28f2f072容器id,-t:显示时间戳
docker logs -f -t 104e28f2f072
#登陆镜像仓库
docker login
#获取镜像
docker pull
#上传镜像
docker push
#查看指定镜像的创建历史。
docker history docker_demo

七. Docker 安装一些常用环境

Docker 安装 Ubuntu: https://www.runoob.com/docker/docker-install-ubuntu.html Docker 安装 CentOS:https://www.runoob.com/docker/docker-install-centos.html Docker 安装 Nginx:https://www.runoob.com/docker/docker-install-nginx.html Docker 安装 Node.js:https://www.runoob.com/docker/docker-install-node.html Docker 安装 MySQL:https://www.runoob.com/docker/docker-install-mysql.html Docker 安装 Redis: https://www.runoob.com/docker/docker-install-redis.html Docker 安装 MongoDB: https://www.runoob.com/docker/docker-install-mongodb.html

八. Docker Compose

1、Docker Compose 介绍

Docker Compose 是一个用来定义和运行复杂应用的 Docker 工具。一个使用 Docker 容器的应用,通常由多个容器组成。使用 Docker Compose 不再需要使用 shell 脚本来启动容器。

Compose 通过一个配置文件来管理多个 Docker 容器,在配置文件中,所有的容器通过 services 来定义,然后使用 docker-compose 脚本来启动,停止和重启应用,和应用中的服务以及所有依赖服务的容器,非常适合组合使用多个容器进行开发的场景。

使用 docker-compose 同时管理多个服务,只需要一行命令 docker compose up -d,就可以从 YML 文件配置中启动一个包含后端项目、前端项目、数据库的完整服务

注意: 由于 Docker Compose 配置需要使用 xml 文件,所以还得知道基本的 yml 文件配置, 参考YAML 入门教程

2、Compose 安装

TIP

若安装的有 Compose,可跳过这一步(macOS 和 windows 版本的 Docker 安装,一般都默认装了 docker compose) 检测是否安装,运行命令:docker-compose --version

sh
# 已安装
$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c

# 未安装
[root@ls-1izl2jyh docker]# docker-compose --version
-bash: docker-compose: command not found

开始安装: (1)运行以下命令以下载 Docker Compose 的当前稳定版本:

sh
sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

要安装其他版本的 Compose,请替换命令中的“v2.2.2”,最新发行的版本地址:https://github.com/docker/compose/releases

(2)将可执行权限应用于二进制文件:

sh
sudo chmod +x /usr/local/bin/docker-compose

(3)创建软链:

sh
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

(4)测试是否安装成功:

sh
$ docker-compose --version
cker-compose version 1.24.1, build 4667896b

注意: 对于 alpine,需要以下依赖包: py-pip,python-dev,libffi-dev,openssl-dev,gcc,libc-dev,和 make。

alpine,是一个重量仅为 5 MB 的最小 Linux 发行版。它还有基本的 linux 工具和一个不错的包管理器 APK。APK 非常稳定,有相当数量的包。由于体积小,在容器中很受欢迎,但是使用上坑也很多,

  • 若 docker-compose 无法安装成功,请尝试手动离线安装
    • a)下载:访问https://github.com/docker/compose/releases,下载 docker-compose-Linux-x86_64(任意版本都行)
    • b)将刚才下载的docker-compose-Linux-x86_64文件上传到 centos7 的/usr/local/bin/目录下
    • c)重命名docker-compose-Linux-x86_64docker-compose
    • d)执行命令sudo chmod +x /usr/local/bin/docker-compose,添加可执行权限
    • e)执行命令docker-compose -v查看版本,输出版本号表示 docker-compose 安装成功

更多安装教程:https://blog.csdn.net/ytangdigl/article/details/103831739

3、Docker Compose 使用

(1)准备 docker-compose.yml 文件

docker-compose.yml文件是一个定义服务网络 的 YAML 文件 。Compose 文件的默认路径是 ./docker-compose.yml,可以使用.yml.yaml 作为扩展名

  • 服务(services): 定义包含应用于为该服务启动的每个容器的配置,就像传递命令行参数一样 docker container create
  • 网络(network): 相当于命令docker network create
  • 卷(volume): 相当于命令docker volume create

例如:一个包含了 docker 容器中tomcatmysqlredis的 docker-compose.yml 文件示例

yaml
version: "2.0"
services:
  #redis 服务
  app_redis:
    image: redis:latest # redis要使用的镜像
    container_name: "app_redis" # redis容器名称
    restart: always #总是重启后启动
    ports: # 相当于run命令中的-p参数
      - "6699:6379"
    environment: # 设置环境变量, environment 的值可以覆盖 env_file 的值 (等同于 docker run --env 的作用)
      TZ: Asia/Shanghai
    command: redis-server --requirepass myredispwd123 # 覆盖容器启动后默认执行的命令, 支持 shell 格式和 [] 格式
    volumes: # 定义容器和宿主机的卷映射关系, 其和 networks 一样可以位于 services 键的二级键和 compose.yml文件 顶级键, 如果需要跨服务间使用则在顶级键定义, 在 services 中引用
      - ./redis/data:/data
    networks: # 将容器加入指定网络 (等同于 docker network connect 的作用), networks 可以位于 compose.yml 文件顶级键和 services 键的二级键
      backend:
        aliases:
          - net_redis
  #mysql服务
  app_mysql:
    image: mysql:5.5
    container_name: "app_mysql"
    ports:
      - "3388:3306"
    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: ql123456
    command: --lower_case_table_names=1
    volumes:
      - ./mysql/conf:/etc/mysql/conf.d
      - ./mysql/data:/var/lib/mysql
    networks:
      backend:
        aliases:
          - net_mysql
  #  tomcat服务
  app_tomcat:
    container_name: app_tomcat
    image: tomcat:7.0.63-jre8
    #总是重启后启动
    restart: always
    #端口映射
    ports:
      - "7070:8080"
    environment:
      TZ: Asia/Shanghai
    logging:
      driver: "json-file"
      options:
        max-size: "500M"
        max-file: "3"
    #挂载
    volumes:
      - ./tomcat/logs:/usr/local/tomcat/logs
      - ./tomcat/webapps:/usr/local/tomcat/webapps
      - ./tomcat/conf:/usr/local/tomcat/conf
    networks:
      backend:
        aliases:
          - net_tomcat
networks:
  backend:

更多字段信息可参考:《docker-compose.yml 配置文件编写详解》

(2)docker-compose.yml 文件重要属性说明

文档结构:

yml
//版本号
version:2.0
//应用名
services:
    app1:
    app2:
    ...
//网络
networks:
    xxxx

image:镜像名称

yml
container_name:容器别名(等同于docker run 中的 --name)
ports:端口映射(等同于docker run 中的 -p)
environment:环境变量(可在环境变量中定义时区、mysql密码等)
command:覆盖容器启动后默认执行的命令,自定义命令
volumes:目录挂载(类似于-v)

数据卷的格式可以是下面多种形式:

yml
volumes:
  # 只是指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)。
  - /var/lib/mysql

  # 使用绝对路径挂载数据卷
  - /opt/data:/var/lib/mysql

  # 以 Compose 配置文件为中心的相对路径作为数据卷挂载到容器。
  - ./cache:/tmp/cache

  # 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/)。
  - ~/configs:/etc/configs/:ro

  # 已经存在的命名的数据卷。
  - datavolume:/var/lib/mysql

如果你不使用宿主机的路径,可以指定一个 volume_driver

yml
volume_driver: mydriver

(3)网络配置(将容器配置到同一个网段)

默认情况下,Compose 会为我们的应用创建一个网络,服务的每个容器都会加入该网络中。这样,容器就可被该网络中的其他容器访问,不仅如此,该容器还能以服务名称作为 Hostname 被其他容器访问。 例如: 上面的docker-compose.yml示例中,每个services的名称既是该服务的hostname,app_redis 服务的 hostname 为 app_redis。

默认情况下,应用程序的网络名称基于 Compose 的工程名称,而项目名称基于 docker-compose.yml 所在目录的名称。如需修改工程名称,可使用 --project-name 标识或 COMPOSE_PORJECT_NAME 环境变量。

假如一个应用程序在名为 myapp 的目录中,并且 docker-compose.yml 如下所示:

yml
version: "2"
services:
  web:
    build: .
    ports:
      - "8000:8000"
  db:
    image: mysql

当我们运行 docker-compose up 时,将会执行以下几步: (1)创建一个名为 myapp_default 的网络 (2)使用 web 服务的配置创建容器,它以 web 这个名称加入网络 myapp_default (3)使用 db 服务的配置创建容器,它以 db 这个名称加入网络 myapp_default (4)容器间可使用服务名称(web 或 db)作为 Hostname 相互访问。例如,web 这个服务可使用 postgres://db:5432 访问 db 容器。

当服务的配置发生更改时,可使用 docker-compose up 命令更新配置。此时,Compose 会删除旧容器并创建新容器。新容器会以不同的 IP 地址加入网络,名称保持不变。任何指向旧容器的连接都会被关闭,容器会重新找到新容器并连接上去。

默认情况下,服务之间可使用服务名称相互访问

一些场景下,默认的网络配置满足不了我们的需求,此时我们可使用 networks 命令自定义网络。networks 命令允许我们创建更加复杂的网络拓扑并指定自定义网络驱动和选项。不仅如此,我们还可使用 networks 将服务连接到不是由 Compose 管理的、外部创建的网络。

yml
version: "2"

services:
  proxy:
    build: ./proxy
    networks:
      - front
  app:
    build: ./app
    networks:
      - front
      - back
  mysql:
    image: mysql
    networks:
      - back

networks:
  front:
    # Use a custom driver
    driver: custom-driver-1
  back:
    # Use a custom driver which takes special options
    driver: custom-driver-2
    driver_opts:
      foo: "1"
      bar: "2"

其中,proxy 服务与 mysql 服务隔离,两者分别使用自己的网络;app 服务可与两者通信。使用 networks 命令,即可方便实现服务间的网络隔离与连接。

参考文章:https://www.jianshu.com/p/35c1dcde95a2

4、常用命令

将 yml 文件丢到任意一个目录,然后进入该目录执行命令

sh
# 启动命令
docker-compose up -d

# 停止命令(停止会删除容器)
docker-compose down

5、docker-compose 参考资料

docker-compose.yml 配置文件编写详解Docker Compose 内网设置(同一局域网下)

九. Docker 部署项目

本节内容见另一篇文章:Docker 部署项目----示例

十. 常见问题归纳

1、ADD 与 COPY 的区别

Dockerfile 中的 COPY 指令和 ADD 指令都可以将主机上的资源复制或加入到容器镜像中,都是在构建镜像的过程中完成的。 COPY 指令和 ADD 指令的唯一区别在于是否支持从远程 URL 获取资源

  • COPY 指令只能从执行 docker build 所在的主机上读取资源并复制到镜像中。
  • ADD 指令还支持通过 URL 从远程服务器读取资源并复制到镜像中。

满足同等功能的情况下,推荐使用 COPY 指令。ADD 指令更擅长读取本地 tar 文件并解压缩。

参考文章:Dockerfile 中的 COPY 和 ADD 指令详解与比较

2. 同名镜像是否会覆盖

构建一个与现有镜头同名的新 docker 镜像,是否会覆盖旧镜头?

答案:不会,但是这个名字会指向你最新的镜像,原镜像仍然存在。

原因:

  • a)Docker 中的镜像没有名称,只有标签.
  • b)签是对图像的引用.多个标签可以指代相同的图像.
  • c)如果重新分配已使用的标记,则原始图像将丢失标记,但将继续存在(它仍可通过其图像 ID 访问,其他标记可能会引用它).

3. CMD 与 RUN 的区别

RUN 是图像构建步骤,RUN 命令之后的容器状态将被提交到 docker 镜像. Dockerfile 可以有许多 RUN 步骤,它们相互叠加以构建图像.

CMD 是启动构建映像时默认情况下容器执行的命令. Dockerfile 只能有一个 CMD.使用 docker run $image $other_command 启动容器时,可以覆盖 CMD.

参考文章:【docker】Dockerfile 文件、run 命令中的 cmd、ENTRYPOINT 命令(两种不同的进程执行方式 shell 和 exec)

4. 容器启动后就自动关闭

原因可能如下: 1、docker 容器运行必须有一个前台进程, 如果没有前台进程执行,容器认为空闲,就会自行退出 2、容器运行的命令如果不是那些一直挂起的命令( 运行 top,tail、循环等),就是会自动退出 3、这个是 docker 的机制问题

解决方案: 1、如果是 egg 项目,去掉--daemon 参数即可,这样就能让他在前台运行 2、如果是其他项目,网上有很多介绍,就是起一个死循环进程,让他不停的循环下去,前台永远有进程执行,那么容器就不会退出了

bash
docker run -d -p 8000:8000 alpine /bin/sh -c "while true; do echo hello world; sleep 1; done"

docker run ubuntu:15.10 /bin/echo "Hello world"

3、其他应用也可以添加-it 参数交互运行,添加-d 参数后台运行,这样就能启动一直停留在后台运行。

bash
docker run -dit -p 8000:8000 alpine /bin/bash

添加-it 参数交互运行
添加-d 参数后台运行
这样就能启动一直停留在后台运行。