- 1. 环境配置的难题
- 2. 虚拟机
- 3. Linux容器
- 4. Docker是什么
- 4.1. Docker的三个概念
- 4.1.1. 镜像(Image)
- 4.1.2. 容器(Container)
- 4.1.3. 仓库(Repository)
- 4.1. Docker的三个概念
- 5. Docker的用途
- 6. Docker的安装和卸载
- 7. image镜像以及相关操作
- 7.1. 镜像加速器
- 7.1.1. Linux修改
- 7.1.2. macOS
- 7.1.3. 检查加速器是否生效
- 7.1.4. gcr.io镜像和quay.io镜像
- 7.1.5. 其他操作
- 7.2. 利用commit将container转换成image镜像
- 7.3. 利用Dockerfile创建镜像
- 7.1. 镜像加速器
- 8. Container容器以及相关操作
- 9. 仓库以及相关操作
- 10. 10 简单总结
- 11. 实例: 制作自己的Docker容器
- 11.1. 编写Dockerfile文件
- 11.2. 创建image文件
- 11.3. 生成容器
- 11.4. CMD 命令
- 11.5. 发布 image 文件
- 12. 其它有用的命令
- 13. 参考
1. 环境配置的难题
软件开发最大的麻烦, 就是环境配置. 用户计算机的环境都不相同,你怎么知道自家的软件,能在那些机器跑起来?
用户必须保证两件事:操作系统的设置,各种库和组件的安装。只有它们都正确,软件才能运行。举例来说,安装一个 Python 应用,计算机必须有 Python 引擎,还必须有各种依赖,可能还要配置环境变量。
环境配置如此麻烦,换一台机器,就要重来一次,旷日费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。
2. 虚拟机
虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 系统里面运行 Linux 系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。
虽然用户可以通过虚拟机还原软件的原始环境。但是,这个方案有几个缺点。
(1)资源占用多
虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有 1MB,虚拟机依然需要几百 MB 的内存才能运行。
(2)冗余步骤多
虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。
(3)启动慢
启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。
3. Linux容器
由于虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。
Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。
由于容器是进程级别的,相比虚拟机有很多优势。
(1)启动快
容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。
(2)资源占用少
容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。
(3)体积小
容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。
总之,容器有点像轻量级的虚拟机,能够提供虚拟化的环境,但是成本开销小得多。
4. Docker是什么
官方文档: https://docs.docker.com/
Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。
Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。
总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
4.1. Docker的三个概念
4.1.1. 镜像(Image)
镜像(Image):类似于虚拟机中的镜像,是一个包含有文件系统的面向Docker引擎的只读模板(!!!只读的!!!)。任何应用程序运行都需要环境,而镜像就是用来提供这种运行环境的。例如一个Ubuntu镜像就是一个包含Ubuntu操作系统环境的模板,同理在该镜像上装上Apache软件,就可以称为Apache镜像。
4.1.2. 容器(Container)
容器(Container):类似于一个轻量级的沙盒,可以将其看作一个极简的Linux系统环境(包括root权限、进程空间、用户空间和网络空间等!!!),以及运行在其中的应用程序(!!!)。Docker引擎利用容器来运行、隔离各个应用!!!。容器是镜像创建的应用实例,可以创建、启动、停止、删除容器,各个容器之间是是相互隔离的,互不影响。注意:镜像本身是只读的,容器从镜像启动时,Docker在镜像的上层(!!!)创建一个可写层(!!!),镜像本身不变。
4.1.3. 仓库(Repository)
仓库(Repository):类似于代码仓库,这里是镜像仓库,是Docker用来集中存放镜像文件的地方。
注意与注册服务器(Registry)的区别:
- 注册服务器是存放仓库的地方,一般会有多个仓库;
- 而仓库是存放镜像的地方,一般每个仓库存放一类镜像!!!,每个镜像!!!利用tag进行区分!!!,比如Ubuntu仓库存放有多个版本(12.04、14.04等)的Ubuntu镜像。
5. Docker的用途
Docker 的主要用途,目前有三大类。
(1)提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
(2)提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
(3)组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
6. Docker的安装和卸载
Docker可以安装在Windows、Linux、Mac等各个平台上。具体可以查看文档Install Docker。也可以查看国内镜像源的安装方式, 比如清华镜像源
先卸载旧版本
# sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
安装依赖包. yum\-utils
提供yum\-config\-manager
组件, device\-mapper\-persistent\-data
和 lvm2
是被devicemapper存储驱动依赖.
# sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
下载repo文件
# wget -O /etc/yum.repos.d/docker-ce.repo http://mirrors.tencent.com/docker-ce/linux/centos/docker-ce.repo
# sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
注: 这里的源是下载docker软件的源, 非docker镜像源
将仓库地址修改为国内源, 比如tuna或腾讯
# sudo sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
# sudo sed -i 's+download.docker.com+mirrors.tencent.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
更新yum缓存
# sudo yum makecache
安装docker engine
# sudo yum install docker-ce docker-ce-cli containerd.io
安装完成之后,可以查看Docker的版本信息:
[root@xxx ~]# docker version
Client:
Version: 1.12.3
API version: 1.24
Go version: go1.6.3
Git commit: 6b644ec
Built:
OS/Arch: linux/amd64
Server:
Version: 1.12.3
API version: 1.24
Go version: go1.6.3
Git commit: 6b644ec
Built:
OS/Arch: linux/amd64
查看Docker的帮助信息:
# docker --help
Docker 需要用户具有 sudo 权限,为了避免每次命令都输入sudo,可以把用户加入 Docker 用户组( 官方文档 )。
sudo usermod -aG docker $USER
Docker 是服务器----客户端架构。命令行运行docker命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动(官方文档)。
# service 命令的用法
$ sudo service docker start
# systemctl 命令的用法
$ sudo systemctl start docker
7. image镜像以及相关操作
Docker 把应用程序及其依赖!!!,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image!!! 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础!!!上,往里面加入 Apache 服务器!!!,形成你的 image。
安装完Docker引擎之后,就可以对镜像进行基本的操作了。
我们从官方注册服务器(https://hub.docker.com)的仓库中pull下CentOS的镜像,前边说过,每个仓库会有多个镜像,用tag标示,如果不加tag,默认使用latest镜像:
7.1. 镜像加速器
注: 除非您修改了 Docker 守护进程的
--registry-mirror
参数 (见官方链接), 否则您将需要完整地指定官方镜像的名称。例如,library/ubuntu、library/redis、library/nginx。不过library是默认组, 可以不加.
国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。国内很多云服务商都提供了国内加速器服务,例如:
- Azure 中国镜像 https://dockerhub.azk8s.cn , 具体见 https://github.com/Azure/container-service-for-azure-china/blob/master/aks/README.md#22-container-registry-proxy
- 阿里云加速器(需登录账号获取)
- 七牛云加速器 https://reg-mirror.qiniu.com , 具体见 https://kirk-enterprise.github.io/hub-docs/#/user-guide/mirror
注: 这三个具体链接都有关于GCR和Quay的镜像地址
由于镜像服务可能出现宕机,建议同时配置多个镜像。
国内各大云服务商均提供了 Docker 镜像加速服务,建议根据运行 Docker 的云平台选择对应的镜像加速服务,具体请参考官方文档。
global | proxy in China | format | example |
---|---|---|---|
dockerhub (docker.io) | dockerhub.azk8s.cn | dockerhub.azk8s.cn/ |
dockerhub.azk8s.cn/microsoft/azure-cli:2.0.61 dockerhub.azk8s.cn/library/nginx:1.15 |
gcr.io | gcr.azk8s.cn | gcr.azk8s.cn/ |
gcr.azk8s.cn/google_containers/hyperkube-amd64:v1.13.5 |
quay.io | quay.azk8s.cn | quay.azk8s.cn/ |
quay.azk8s.cn/deis/go-dev:v1.10.0 |
七牛镜像加速地址:
- Docker Hub:https://reg-mirror.qiniu.com
- GCR:https://gcr-mirror.qiniu.com
- Quay:https://quay-mirror.qiniu.com
7.1.1. Linux修改
Ubuntu 16.04+、Debian 8+、CentOS 7 对于使用 systemd 的系统,请在 /etc/docker/daemon.json
中写入如下内容(如果文件不存在请新建该文件)
{
"registry-mirrors": [
"https://dockerhub.azk8s.cn",
"https://reg-mirror.qiniu.com"
]
}
注意,一定要保证该文件符合 json 规范,否则 Docker 将不能启动。
之后重新启动服务。
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
注意:如果您之前查看旧教程,修改了 docker.service 文件内容,请去掉您添加的内容(--registry-mirror=https://dockerhub.azk8s.cn)。
7.1.2. macOS
对于使用 macOS 的用户,在任务栏点击 Docker Desktop 应用图标 -> Perferences... -> Daemon -> Registry mirrors。在列表中填写加速器地址 https://dockerhub.azk8s.cn。修改完成之后,点击 Apply & Restart 按钮,Docker 就会重启并应用配置的镜像地址了。
可以将默认仓库改成国内的镜像网站,具体的修改方法见官方链接。
7.1.3. 检查加速器是否生效
修改后查看加速器是否生效, 执行docker info, 如果有如下内容, 说明成功
Registry Mirrors:
https://dockerhub.azk8s.cn/
7.1.4. gcr.io镜像和quay.io镜像
国内无法直接获取 gcr.io/* 镜像,我们可以将 gcr.io/
替换为 gcr.azk8s.cn/
,例如
$ docker pull gcr.io/google_containers/hyperkube-amd64:v1.9.2
$ docker pull gcr.azk8s.cn/google_containers/hyperkube-amd64:v1.9.2
注: k8s.gcr.io
会被重定向到gcr.io/google-containers
, 下面image的url是一样的
k8s.gcr.io/pause-amd64:3.1
gcr.io/google_containers/pause-amd64:3.1
7.1.5. 其他操作
# 查看centos镜像是否存在
[root@xxx ~]# docker search centos
# 利用pull命令获取镜像
[root@localhost ~]# docker pull library/centos
Using default tag: latest
latest: Pulling from library/centos
a02a4930cb5d: Pull complete
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
Status: Downloaded newer image for centos:latest
# 列出本机的所有 image 文件, 也可用命令docker image ls
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest fce289e99eb9 2 months ago 1.84kB
centos latest 1e1148e4cc2c 3 months ago 202MB
# 删除 image 文件
$ docker image rm [imageName]
docker image pull是抓取 image 文件的命令。library/centos是 image 文件在仓库里面的位置,其中library是 image 文件所在的组!!!,centos是 image 文件的名字。
因此,上面的命令可以写成下面这样。
$ docker image pull centos
image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作。
为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库 Docker Hub 是最重要、最常用的 image 仓库。此外,出售自己制作的 image 文件也是可以的。
以上是下载一个已有镜像, 学会使用image文件后, 接下来就是, 如何可以生成image文件? 如果要推广自己的软件, 必须要制作自己的image文件.
有两种方法可以来新建自有镜像
7.2. 利用commit将container转换成image镜像
利用镜像启动一个容器后进行修改 ==> 利用commit提交更新后的副本
[root@xxx ~]# docker run -it centos:latest /bin/bash # 启动一个容器
[root@5c42568d06c2 /]# # 这里命令行形式变了,表示已经进入了一个新环境
[root@5c42568d06c2 /]# git --version # 此时的容器中没有git
bash: git: command not found
[root@5c42568d06c2 /]# yum install git # 利用yum安装git
......
[root@5c42568d06c2 /]# git --version # 此时的容器中已经装有git了
git version 1.8.3.1
此时利用exit退出该容器,然后查看docker中运行的程序(容器):
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5c42568d06c2 centos:latest "/bin/bash" 38 minutes ago Exited (0) 23 seconds ago hardcore_elgamal
将容器转化成一个镜像!!!, 即执行commit操作!!!, 完成后使用docker images查看:
[root@localhost dockertest]# docker commit -m "centos with git & tsinghua mirro" -a "gerrylee" 5c42568d06c2 gerrylee/centos:git
sha256:b4eeaa116d8fa45882f7e97ab2a80557d8c1d9234df225be8f6dfc9061c2c44a
[root@localhost dockertest]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
gerrylee/centos git b4eeaa116d8f 3 minutes ago 513MB
hello-world latest fce289e99eb9 2 months ago 1.84kB
centos latest 1e1148e4cc2c 3 months ago 202MB
其中, -m指定说明信息;-a指定用户信息;5c42568d06c2代表容器的id;gerrylee/centos:git指定目标镜像的用户名、仓库名和 tag 信息。注意这里的用户名gerrylee,后边会用到。
此时Docker引擎中就有了我们新建的镜像gerry/centos:git,此镜像和原有的CentOS镜像区别在于多了个Git工具。此时我们利用新镜像创建的容器,本身就自带git了。
[root@localhost dockertest]# docker run -it gerrylee/centos:git /bin/bash
[root@f1356f4017f3 /]# git --version
git version 1.8.3.1
利用exit退出容器. 注意此时docker引擎中就有两个容器, 可以使用docker ps -a查看.
[root@localhost dockertest]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f1356f4017f3 gerrylee/centos:git "/bin/bash" 57 seconds ago Exited (127) 21 seconds ago compassionate_merkle
5c42568d06c2 centos:latest "/bin/bash" About an hour ago Exited (0) About an hour ago hardcore_elgamal
7.3. 利用Dockerfile创建镜像
它是一个文本文件, 用来配置image. Docker根据该文件通过docker build命令生成二进制的image文件. 一个简易的Dockerfile文件如下. 官方说明: Dockerfile reference
# 说明该镜像以哪个镜像为基础
FROM centos:latest
# 构建者的基本信息
MAINTAINER gerrylee
# 在build这个镜像时执行的操作
RUN yum update -y
RUN yum install -y git
# 拷贝本地文件到镜像中
COPY ./* /home/Gerry/project/dockertest/
使用build命令构建镜像
[root@localhost dockertest]#docker build -t="gerrylee/centos:gitdir" .
其中-t用来指定新镜像的用户信息、tag等。最后的点表示在当前目录寻找Dockerfile。
构建完成之后,同样可以使用docker images命令查看:
[root@localhost dockertest]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
gerrylee/centos gitdir f82f176ad3a1 8 seconds ago 478MB
gerrylee/centos git b4eeaa116d8f 16 minutes ago 513MB
hello-world latest fce289e99eb9 2 months ago 1.84kB
centos latest 1e1148e4cc2c 3 months ago 202MB
8. Container容器以及相关操作
image文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。
在前边镜像的章节中,我们已经看到了如何基于镜像启动一个容器,即docker run操作。
[root@xxx ~]# docker run -it centos:latest /bin/bash
这里-it是两个参数:-i和-t。前者表示打开并保持stdout,后者表示分配一个终端(pseudo-tty)。此时如果使用exit退出,则容器的状态处于Exit,而不是后台运行。如果想让容器一直运行,而不是停止,可以使用快捷键 ctrl+p ctrl+q 退出,此时容器的状态为Up。
docker container run命令会从 image 文件,生成一个正在运行的容器实例。有些容器不会自动终止,因为提供的是服务。比如,安装运行 Ubuntu 的 image,就可以在命令行体验 Ubuntu 系统。
注意,docker container run命令具有自动抓取 image 文件的功能。如果发现本地没有指定的 image 文件,就会从仓库自动抓取。因此,前面的docker image pull命令并不是必需的步骤。
除了这两个参数之外,run命令还有很多其他参数。其中比较有用的是-d后台运行:
[root@xxx ~]# docker run centos:latest /bin/bash -c "while true; do echo hello; sleep 1; done"
[root@xxx ~]# docker run -d centos:latest /bin/bash -c "while true; do echo hello; sleep 1; done"
这里第二条命令使用了-d参数,使这个容器处于后台运行的状态,不会对当前终端产生任何输出,所有的stdout都输出到log,可以使用docker logs container_name/container_id查看。
启动、停止、重启容器命令:
[root@xxx ~]# docker start container_name/container_id
[root@xxx ~]# docker stop container_name/container_id
[root@xxx ~]# docker restart container_name/container_id
后台启动一个容器后,如果想进入到这个容器,可以使用attach命令或exec命令:
[root@xxx ~]# docker attach container_name/container_id
attach命令进入后, 如果从这个stdin中exit, 会导致容器的停止.
使用下面命令不会停止容器, -u 0代表root用户
#
[root@xxx ~]# docker exec -u 0 -it container_name/container_id /bin/bash
列出所有容器
# 列出本机正在运行的容器
$ docker container ls
# 列出本机所有容器,包括终止运行的容器
$ docker container ls --all
上面命令的输出结果之中,包括容器的 ID。
对于那些不会自动终止的容器,必须使用docker container kill 命令手动终止。
$ docker container kill [containID]/[container_name]
终止运行的容器文件,依然会占据硬盘空间,可以使用docker container rm命令删除。
删除容器的命令前边已经提到过了:
[root@xxx ~]# docker rm container_name/container_id
运行上面的命令之后,再使用docker container ls --all
命令,就会发现被删除的容器文件已经消失了。
9. 仓库以及相关操作
Docker官方维护了一个DockerHub的公共仓库,里边包含有很多平时用的较多的镜像。除了从上边下载镜像之外,我们也可以将自己自定义的镜像发布(push)到DockerHub上。
在镜像操作章节中,我们新建了一个xianhu/centos:git镜像。
(1) 访问https://hub.docker.com/,如果没有账号,需要先注册一个。
(2) 利用命令docker login登录DockerHub,输入用户名、密码即可登录成功:
[root@localhost ~]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: gerrylee
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
(3) 将本地镜像推动到DockerHub上, 这里的名字要和登录时候的username一致:
# 成功推送
[root@localhost dockertest]# docker push gerrylee/centos:git
The push refers to repository [docker.io/gerrylee/centos]
2767ddbb75ff: Pushed
071d8bd76517: Mounted from library/centos
git: digest: sha256:d38bf27d08edeb0b4cd74b4c1c7582e13a83a27602b204142b06e94f738a87cd size: 742
# 推送失败
[root@localhost dockertest]# docker push xxx/centos:git
The push refers to repository [docker.io/xxx/centos]
An image does not exist locally with the tag: xxx/centos
(4) 以后别人可以从你的仓库下载合适的镜像了
[root@localhost dockertest]# docker pull gerrylee/centos:git
git: Pulling from gerrylee/centos
Digest: sha256:d38bf27d08edeb0b4cd74b4c1c7582e13a83a27602b204142b06e94f738a87cd
Status: Image is up to date for gerrylee/centos:git
从这里当然也可以看到
对应于镜像的两种创建办法, 镜像的更新也是两种:
- 创建容器后更改, 之后commit生成镜像, 然后push到仓库中.
- 更新Dockerfile. 一般建议这种方法.
10. 10 简单总结
从仓库(一般为DockerHub)下载(pull)一个镜像,Docker执行run方法得到一个容器,用户在容器里执行各种操作。Docker执行commit方法将一个容器转化为镜像。Docker利用login、push等命令将本地镜像推送(push)到仓库。其他机器或服务器上就可以使用该镜像去生成容器,进而运行相应的应用程序了。
11. 实例: 制作自己的Docker容器
下面我以 koa-demos 项目为例,介绍怎么写 Dockerfile 文件,实现让用户在 Docker 容器里面运行 Koa 框架。
作为准备工作,请先下载源码。
$ git clone https://github.com/ruanyf/koa-demos.git
$ cd koa-demos
11.1. 编写Dockerfile文件
首先. 在项目的根目录下, 新建一个文件.dockerignore, 写入下面内容
.git
node_modules
npm-debug.log
上面代码表示,这三个路径要排除,不要打包进入 image 文件。如果你没有路径要排除,这个文件可以不新建。
然后,在项目的根目录下,新建一个文本文件 Dockerfile,写入下面的内容。
FROM node:8.4
COPY . /app
WORKDIR /app
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 3000
上面代码含义如下:
- FROM node:8.4:该 image 文件继承官方的 node image,冒号表示标签,这里标签是8.4,即8.4版本的 node。
- COPY . /app:将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入 image 文件的/app目录。
- WORKDIR /app:指定接下来的工作路径为/app。
- RUN npm install:在/app目录下,运行npm install命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。
- EXPOSE 3000:将容器 3000 端口暴露出来, 允许外部连接这个端口。
11.2. 创建image文件
有了Dockerfile文件, 就可以使用docker image build命令创建image文件了.
$ docker image build -t koa-demo .
# 或者
$ docker image build -t koa-demo:0.0.1 .
上面代码中,-t参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是latest。最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。
如果运行成功,就可以看到新生成的 image 文件koa-demo了。
$ docker image ls
11.3. 生成容器
docker container run命令会从 image 文件生成容器。
$ docker container run -p 8000:3000 -it koa-demo /bin/bash
# 或者
$ docker container run -p 8000:3000 -it koa-demo:0.0.1 /bin/bash
上面命令的各个参数含义如下:
- -p参数:容器的 3000 端口映射到本机的 8000 端口。
- -it参数:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。
- koa-demo:0.0.1:image 文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)。
- /bin/bash:容器启动以后,内部第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell。
如果一切正常, 运行上面命令后,就会返回一个命令行提示符
root@66d80f4aaf1e:/app#
这表示你已经在容器里面了,返回的提示符就是容器内部的 Shell 提示符。执行下面的命令。
root@66d80f4aaf1e:/app# node demos/01.js
这时,Koa 框架已经运行起来了。打开本机的浏览器,访问 http://127.0.0.1:8000,网页显示"Not Found",这是因为这个 demo 没有写路由。
这个例子中,Node 进程运行在 Docker 容器的虚拟环境里面,进程接触到的文件系统和网络接口都是虚拟的,与本机的文件系统和网络接口是隔离的,因此需要定义容器与物理机的端口映射(map)。
现在,在容器的命令行,按下 Ctrl + c停止 Node 进程,然后按下 Ctrl + d (或者输入 exit)退出容器。此外,也可以用docker container kill终止容器运行。
# 在本机的另一个终端窗口,查出容器的 ID
$ docker container ls
# 停止指定的容器运行
$ docker container kill [containerID]
容器停止运行之后,并不会消失,用下面的命令删除容器文件。
# 查出容器的 ID
$ docker container ls --all
# 删除指定的容器文件
$ docker container rm [containerID]
也可以使用docker container run命令的--rm参数,在容器终止运行后自动删除容器文件。
$ docker container run --rm -p 8000:3000 -it koa-demo /bin/bash
11.4. CMD 命令
上一节的例子里面,容器启动以后,需要手动输入命令node demos/01.js。我们可以把这个命令写在 Dockerfile 里面,这样容器启动以后,这个命令就已经执行了,不用再手动输入了。
FROM node:8.4
COPY . /app
WORKDIR /app
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 3000
CMD node demos/01.js
上面的 Dockerfile 里面,多了最后一行CMD node demos/01.js,它表示容器启动后自动执行node demos/01.js。
你可能会问,RUN命令与CMD命令的区别在哪里?简单说,RUN命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;CMD命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个RUN命令,但是只能有一个CMD命令。
注意,指定了CMD命令以后,docker container run命令就不能附加命令了(比如前面的/bin/bash),否则它会覆盖CMD命令。现在,启动容器可以使用下面的命令。
$ docker container run --rm -p 8000:3000 -it koa-demo:0.0.1
11.5. 发布 image 文件
容器运行成功后,就确认了 image 文件的有效性。这时,我们就可以考虑把 image 文件分享到网上,让其他人使用。
首先,去 hub.docker.com 或 cloud.docker.com 注册一个账户。然后,用下面的命令登录。
$ docker login
接着,为本地的 image 标注用户名和版本。
$ docker image tag [imageName] [username]/[repository]:[tag]
# 实例
$ docker image tag koa-demos:0.0.1 ruanyf/koa-demos:0.0.1
也可以不标注用户名,重新构建一下 image 文件。
$ docker image build -t [username]/[repository]:[tag] .
最后,发布 image 文件。
$ docker image push [username]/[repository]:[tag]
发布成功以后,登录 hub.docker.com,就可以看到已经发布的 image 文件。
12. 其它有用的命令
docker 的主要用法就是上面这些,此外还有几个命令,也非常有用。
(1)docker container start
前面的docker container run命令是新建容器,每运行一次,就会新建一个容器。同样的命令运行两次,就会生成两个一模一样的容器文件。如果希望重复使用容器,就要使用docker container start命令,它用来启动已经生成、已经停止运行的容器文件。
$ docker container start [containerID]
(2)docker container stop
前面的docker container kill命令终止容器运行,相当于向容器里面的主进程发出 SIGKILL 信号。而docker container stop命令也是用来终止容器运行,相当于向容器里面的主进程发出 SIGTERM 信号,然后过一段时间再发出 SIGKILL 信号。
$ bash container stop [containerID]
这两个信号的差别是,应用程序收到 SIGTERM 信号以后,可以自行进行收尾清理工作,但也可以不理会这个信号。如果收到 SIGKILL 信号,就会强行立即终止,那些正在进行中的操作会全部丢失。
(3)docker container logs
docker container logs命令用来查看 docker 容器的输出,即容器里面 Shell 的标准输出。如果docker run命令运行容器的时候,没有使用-it参数,就要用这个命令查看输出。
$ docker container logs [containerID]
(4)docker container exec
docker container exec命令用于进入一个正在运行的 docker 容器。如果docker run命令运行容器的时候,没有使用-it参数,就要用这个命令进入容器。一旦进入了容器,就可以在容器的 Shell 执行命令了。
$ docker container exec -it [containerID] /bin/bash
(5)docker container cp
docker container cp命令用于从正在运行的 Docker 容器里面,将文件拷贝到本机。下面是拷贝到当前目录的写法。
$ docker container cp [containID]:[/path/to/file] .
13. 参考
https://zhuanlan.zhihu.com/p/23599229
http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html