docker 入门及构建镜像

862 阅读6分钟

前言:为什么要 docker?

  • 更高效的利用系统资源
  • 更快速的启动时间
  • 一致的运行环境
  • 持续交付和部署

对比虚拟机

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为 MB 一般为 GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般几十个

几个基本概念

镜像(Image)

镜像是一个虚拟的概念,相当于一个 root 文件系统。提供了容器运行时所需的程序、库、资源、配置文件以及运行时所需要的配置参数等内容。应用程序及其依赖,都打包在 Image 中,通过这个文件,才能生成 Docker 容器。

容器(Container)

镜像和容器,类似面向对象的 类 和 实例。容器就类似于实例。容器是镜像运行起来的实体,可以被创建、启动、停止、删除等操作。

仓库(Registry)

保存镜像的地方。Docker Hub。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。

例如想要使用 MySQL ,按照官方文档指令,docker pull mysql 即可。

正文

食用前提:

  • 已经安装好 docker。安装文档
  • 最好配置了镜像加速(可选)。因为国内访问 Docker 镜像,速度都比较慢,为了更快访问 Docker 镜像,可以配置第三方加速器如:网易、USTC、阿里云。镜像加速配置方式。链接文章拉到底部,对 Windows 和 macOS 都有配置教程。

获取镜像

用法:

docker pull  [选项]   [Docker Registry 地址[:端口号]/]仓库名[:标签]

我们拿 nginx 举例,获取最新的 nginx 镜像

$ docker pull nginx

latest: Pulling from library/nginx
54fec2fa59d0: Pull complete
4ede6f09aefe: Pull complete
f9dc69acb465: Pull complete
Digest: sha256:86ae264c3f4acb99b2dee4d0098c40cb8c46dcf9e1148f05d3a51c4df6758c12
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

查看该镜像是否已经成功 pull

$ docker image ls

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              602e111c06b6        4 days ago          127MB

有如上信息输出,说明 TAG 为 latest 的 nginx 已经成功 pull

还有其他 版本 的 nginx 可供使用, dockerhub 地址

运行容器

有了镜像之后,我们能以镜像为基础,创建出相应的容器。以上一步获取的 nginx 为例,最简单的执行,按照上一步获取的 IMAGE ID,执行 docker run

$ docker run 602e111c06b6


此时拥有 nginx 配置环境的容器即被启动了,打开另一个 tab ,查看该容器的运行状态:

$ docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
c76674325dc9        602e111c06b6        "nginx -g 'daemon of…"   2 minutes ago       Up 2 minutes        80/tcp

可以看到这个 container 的状态(STATUS)为「Up 2 minutes」。根据 IMAGE ID,可以知道这是上一步启动的 nginx image.

接下来进一步在本地电脑上展示我们跑起来的容器(也就是外部访问容器的实现)------对容器进行端口映射:

在 docker run 时候通过 -p 或 -P 参数来启用

$ docker run -p 8082:80 602e111c06b6

http://localhost:8082/ 就可以访问到我们跑起来的 nginx 内容了。

还可以给跑起来的容器命名,参数:--name

$ docker run -p 8082:80 --name test-nginx 602e111c06b6
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
f0bbe4ccbc97        602e111c06b6        "nginx -g 'daemon of…"   7 seconds ago       Up 5 seconds        0.0.0.0:8082->80/tcp   test-nginx

使用 Dockerfile 定制镜像

DOckerfile 就是一个文本文件,用来构建一个镜像,文本内容包含了一条条用来构建镜像所需要的指令和说明。

Dockerfile 的指令有:

  • COPY:从上下文目录中复制文件或者目录到容器里指定路径
  • ADD
  • CMD:类似于 RUN 指令,用于运行程序
  • ENV:设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量
  • EXPOSE:声明端口
  • FROM:定制需要的基础镜像
  • LABEL
  • STOPSIGNAL
  • USER:指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户
  • VOLUME:定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
  • WORKDIR:指定工作目录
  • ONBUILD (when combined with one of the supported instructions above)

其他更详细的解释,见官方文档

踩坑:创建 Dockerfile 建议不要用图形化创建,避免存在隐形的后缀。文件名字即为 Dockerfile,无后缀。

例子一

创建一个最简单的 Dockerfile,达到的效果是,在构建镜像时输出一段文字

⋊> ~/Desktop mkdir test-docker-file                                                      14:15:15
⋊> ~/Desktop cd test-docker-file/                                                        14:15:29
⋊> ~/D/test-docker-file touch Dockerfile                                                 14:15:36
⋊> ~/D/test-docker-file vi Dockerfile

编辑 Dockerfile 的内容是:

FROM nginx
RUN echo '这是一个本地构建的nginx镜像'

退出 vim 编辑,然后执行:

⋊> ~/D/test-docker-file docker build -t test-docker-file .      


Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
 ---> 602e111c06b6
Step 2/2 : RUN echo '这是一个本地构建的nginx镜像'
 ---> Running in e3bdfe16c57b
这是一个本地构建的nginx镜像
Removing intermediate container e3bdfe16c57b
 ---> 06c60b75a00c
Successfully built 06c60b75a00c
Successfully tagged test-docker-file:latest

如我们所料,第二步输出了 “这是一个本地构建的nginx镜像”

例子二:为一个 Web 程序定制镜像

首先,我们准备一个 vue 项目,脚手架一把嗦一个:

⋊> ~/D/test-docker-file cd ../                                                           14:22:10
⋊> ~/Desktop vue create test-docker

// 创建成功之后

⋊> ~/Desktop cd test-docker                                                              14:28:40
⋊> ~/D/test-docker on master  npm run serve                                              14:29:01

// 在 8080 端口访问项目正常,还是熟悉的 vue 主页

接下来编写 Dockerfile,对该项目进行定制,我们想要实现的效果:

  1. 定制一个镜像
  2. 跑起来后,能从容器外部访问该程序

创建一个.dockerignore 文件,避免镜像中存在太多多余的文件,类似 .gitignore。文件内容:

./node_modules

Dockerfile 内容如下:

FROM node
WORKDIR /app
COPY . /app/

RUN npm install -g cnpm --registry=https://registry.npm.taobao.org
RUN cnpm install

EXPOSE 8080

CMD [ "npm", "run", "serve" ]

解释:

  • 拉取基础镜像 node
  • 创建工作目录 /app
  • 将当前的上下文拷贝进工作目录 /app
  • 更换 npm 源头为淘宝源
  • 执行 npm install
  • 暴露 80 端口供容器外部访问
  • 在 docker run 的时候执行 "npm run serve"

执行:

docker build -t test-docker-vue .

运行过程:

⋊> ~/D/test-docker on master ⨯ docker build -t test-docker-vue .                         14:52:00

Sending build context to Docker daemon  808.4kB
Step 1/7 : FROM node

// 省略

Removing intermediate container 5662dc5aae9e
 ---> 42894d24de49
Step 6/7 : EXPOSE 80
 ---> Running in 3f3524d92c02
Removing intermediate container 3f3524d92c02
 ---> 8b37aa222f33
Step 7/7 : CMD [ "npm", "run", "serve" ]
 ---> Running in eeee0de97656
Removing intermediate container eeee0de97656
 ---> 94275461b4d8
Successfully built 94275461b4d8
Successfully tagged test-docker-vue:latest

如上,我们成功的构建了一个镜像,id 为 94275461b4d8,tagged 为 test-docker-vue:latest。

命令行查看当前所有的 image:

docker image ls

可以看到存在一条数据:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test-docker-vue     latest              94275461b4d8        26 minutes ago      1.2GB

将这个 image 跑起来,并将本地的 8083 端口映射至容器的 8080 端口:

docker run -p 8083:8080 94275461b4d8

等待运行结果。

此时说明容器已经正常跑起来了,我们可以访问 http://localhost:8083/

一切正常。

代码全部上传至 GitHub,传送门

参考