0. 前言

dokcer是什么?

dokcer是用Go语言开发的应用容器引擎,基于容器化,沙箱机制的应用部署技术,可适用于自动化测试、打包,持续集成和发布应用等场景。

docker基于容器化,沙箱机制,可使用较少的命令和脚本快速部署应用,一次构建,多处移植使用。再配合shell等脚本语言,可实现脚本化一键部署

docker 大部分都是依赖于命令执行的,简单易上手

docker现在已经成为比较受欢迎的serverless(无服务器架构)服务的基础架构。包括阿里云、亚马孙在内的云计算服务商都采用docker来打造serverless服务平台。

与此同时,基于docker的微服务架构也如火如茶的出现。

由此可见,docker容器技术非同一般

一. dokcer的运作

docker是沙箱机制,容器化部署技术,它主要作用在于通过运行容器来实现应用部署,而容器基于镜像运行。

简单的来说,将你的项目和依赖包(基础镜像)打成一个带有启动指令的项目镜像, 然后在服务器创建一个容器,让镜像在容器内运行,从而实现项目的部署。

服务器就是容器的宿主机,docker容器与宿主机是相互隔离的。

它不仅仅可以部署项目,还可以用于数据库的搭建,nginx服务搭建,nodejs、php等语言环境的搭建。

二. docker的三个概念

docker三个概念:镜像(Image)、容器(Container)、仓库(Repository)

同时还需要知道他们三个之前的关系。

  • 镜像

docker镜像是使用Dokerfile脚本,将你的应用以及应用的依赖包构建而成的一个应用包,它通常带有改应用的启动命令。而这些命令会在容器启动的时候被执行,也就是说相应的应用再启动容器时被启动。

镜像的创建,需要通过配置Dockerfile脚本,然后执行dokcer build来创建。

举个例子:

docker build -t mydocker/node-server:v1
  • 容器

容器是使用 docker run --name 容器名 镜像 命令创建的,独立于宿主机(服务器)的沙箱,也可以理解为一个带有特殊结构的盒子,它在创建时会自动执行镜像自带的一些指令,从而实现应用的运行。

狭隘的将,容器的主要作用就在于给镜像提供运行空间和环境,并执行镜像的指令。

  • 仓库

顾名思义,仓库是用来存东西的, 但不是用来存容器的,而是存储docker镜像。可以把docker镜像通过push命令推送到docker仓库,然后就可以在任何可以使用docker命令的地方通过pull命令把这个镜像拉取下来。

三. docker镜像、容器、容器三者之间的关系

docker的使用方式主要有命令、Dockerfile脚本以及shell脚本三种。也就是说,可以把docker当作命令行工具来使用。

docker是沙箱机制,容器化部署技术,它主要作用在于通过运行容器来实现应用的部署,而容器则基于镜像运行。

因此,首先要有镜像,有了镜像才能基于镜像创建容器,才能把镜像存储在仓库。

于是可以这样去理解,镜像是基础,容器是镜像使用者,仓库是镜像的管理员。容器和仓库都是围绕着镜像来运作的,是对镜像的管理和使用。

另外,镜像、容器、仓库都有一套自己的docker命令,用于前期的构建以及后期的维护。

四. docker 基本开发流程

基本开发流程如下:

  • 1.寻找基础镜像
  • 2.基础镜像编写Dockerfile文件
  • 3.根据Dockerfile脚本创建项目镜像
  • 4.将创建的镜像推送到docker仓库
  • 5.基于镜像创建并运行docker容器(实现最终部署)

这个流程只开发一次,后期只做简单的维护就好。

五. Dockerfile 脚本

经过上边的一系列描述,基本上大部分工作都是围绕镜像来做的,所以我们首先学习docker镜像。

1. 基础镜像
  • 什么是基础镜像?

docker有这么一种机制,在构建镜像时,可以依赖于一个父镜像作为底层镜像,与当前正要构建的镜像打包在一起,从而构成一个全新的镜像,而这个被作为依赖的父镜像,就是基础镜像。

  • 为什么有这样的需要呢?

比如,通常开发一个nodejs应用,它不是随处可运行的,它的运行需要依赖于操作系统环境和nodejs运行环境。

因此,一个node项目镜像是无法运行起来的,它需要依赖一个基础镜像,这个基础镜像就是nodejs镜像,nodejs镜像内包含了操作系统环境和nodejs环境。这样nodejs镜像+node项目构建出来的项目镜像才能完整的运行起来。

因此,在配置项目Dockerfile创建镜像脚本之前,需要先确立一个基础镜像。

基础镜像是如何使用的呢?主要是通过在Dockerfile脚本中使用From命令指定依赖一个父镜像(基础镜像)。

* 基础镜像通常不需要自己创建,dokcer官方有提供很多基础镜像供用户使用,比如nodejs镜像,java镜像,mongodb镜像,nginx镜像等等。
* 除了官方提供的,你还可以寻找第三方源提供的基础镜像。
2. Dockerfile脚本构成

docker镜像是通过配置Dockerfile脚本,然后执行docker build 命令来创建。

Dockerfile文件可通过nano Dockerfile命令或者touch Dockerfile命令来创建。

Dockerfile脚本文件通常放在项目的根目录下。也可以放在他文件,但执行docker build 时需要指定文件路径。

(1)Dockerfile脚本语法和结构

Dockerfile 语法由两部分构成,分别是注解和指令 + 参数
使用 “#” 可实现注释
Dockerfile 脚本通常分为以下四个部分:

  • 基础镜像信息
  • 维护者信息
  • 镜像操作指令
  • 容器启动时执行的指令
(2)Dockerfile脚本案例

下面直接来看个例子说明,这是我的开源博客后台sinn-server的Dockerfile脚本。
如下:

# 基础镜像信息
From registry.cn-hangzhou.aliyuncs.com/sessionboy/node:7.5

# 维护者信息
MAINTAINER sessionboy <postmaster@boyagirl.com>

# 镜像操作指令
COPY ./ /sinn-server
WORKDIR /sinn-server
RUN npm install
EXPOSE 8080

# 容器启动时执行的指令
ENTRYPOINT ["node","bin/run"]
(3)Dockerfile语法解剖

Dockerfile有十几条命令可用于创建镜像,下面根据四个不同功能模块来介绍这些命令。

A——基础镜像信息

基础镜像信息只有一个From命令,指定依赖的基础镜像。

  • From

指定依赖的基础镜像,如果不存在就会从docker官方仓库寻找

# docker官方镜像仓库
# 指定docker官方仓库的新版nodejs镜像作为基础镜像
From node:latest
更多配置......

# 第三方镜像仓库,比如阿里云的 “https://dev.aliyun.com/search.html ”
# 指定标签为7.5的"registry.cn-hangzhou.aliyuncs.com/sessionboy/node"镜像作为基础镜像
From registry.cn-hangzhou.aliyuncs.com/sessionboy/node:7.5   
更多配置……
B——维护者信息

维护者信息也只有一次MAINTAINER指令,用于描述该镜像的维护者信息

  • MAINTAINER

#MAINTAINER

MAINTAINER sessionboy postmaster@boyagirl.com

C——镜像操作指令

镜像的操作指令有很多,逐一进行简单讲解。

  • COPY

CPOY指令用于拷贝宿主机的源目录/文件到容器内的某个目录,接受两个参数,原目录路径和容器内目录路径。

# 将“./”(当前目录)的文件拷贝到容器内的“/sinn-server” 目录
COPY ./ /sinne-server
  • ADD

功能和语法与COPY指令基本相同,不同在于使用ADD指令拷贝时,如果拷贝的是压缩文件,拷贝到容器中时会自动解压为目录

# 将当前的/server 目录拷贝到容器中的/project目录
ADD /server /project
  • WORKDIR

指定RUN、CMD、ENTRYPOINT指令的工作目录

  • RUN

RUN是核心指令,它接受命令作为参数并用于创建镜像,。命令较多时可使用“\”换行

……
RUN ["/bin/bash", "-c", "echo hello"]
RUN rm ./tmp \
    npm install
……
  • USER

USER命令用于设置运行容器 UID

# 指定容器的UID为23541
USER  23541
  • VOLUME

VOLUME用于让你的容器访问宿主机上的目录。一般用来存放数据库和需要使用的数据。

# 指定容器可访问宿主机(服务器)的“/data”目录和“/home”目录
VOLUME ["/data",'"/home"]
  • ONBUILD

配置当所创建的镜像作为其他新创建镜像的基础镜像时,所执行的操作指令。

  • ENV

ENV命令用于设置环境变量,在容器内被脚本或者程序调用。

# 设置环境变量 NODE_ENV 为 production
ENV NODE_ENV  production
  • EXPOSE

EXPOSE 用来指定端口,使容器内的应用可以通过端口和外界交互。

# 对外暴露8080端口
EXPOSE 8080
D——容器启动时执行的命令
  • CMD

指定容器启动时执行的命令,每个Dockerfile只能有一条CMD命令,可被docker run提供的参数覆盖。

# 三种方式
CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式
CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用    
CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数
  • ENTRYPOINT

容器启动后执行的命令,与CMD命令不同的是,它不会被docker run提供的参数覆盖。

# 两种方式
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2(shell中执行)。

六. dokcer镜像的创建

为了操作方便,docker提供了一套镜像的操作命令

1. 创建镜像

镜像是基于Dockerfile脚本, 使用docker build 命令创建的,上面已经对Dockerfile做了详细的剖析,下面来说说如何使用Dockerfile脚本创建。

语法:

docker build [OPTIONS] PATH

OPTIONS作为对容器的配置项,内容有很多,可以到这里查看 Dockerbuild 命令, 一般不建议配置,使用默认的就好。

PATH为DockerFile脚本所在的目录,通常放在项目的根目录下,使用‘.’ 表示
-t标记用来添加tag,指定新的镜像信息,例如镜像名称,标签

# 使用当前目录的Dockerfile脚本创建名为“registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn”的镜像,并标记为v1(标签,也可以理解为版本号)

docker build -t registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn:v1 .

# 指定使用github.com/creack/docker-firefox的Dockerfile脚本创建镜像
docker build github.com/creack/docker-firefox

为了操纵方便,我们再根目录下建立一个名为build.sh 的shell脚本来执行这些命令,如下:

# build.sh
docker build -t registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn:v1 .

sh build.sh 进行执行,看到Successfully,说明镜像已经创建成功。

使用命令docker images 可以查看本地所有的docker镜像

2. 本地镜像管理

命令如下:

  • 1.查看镜像:dokcer images
# 列出本地所有镜像
  docker images
  • 2.删除镜像:dokcer rmi 镜像
# 删除镜像
  docker rmi  registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn
  • 3.镜像重命名:dokcer tag 原镜像tag 新镜像tag
# 将镜像registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn:v1重新标记为newImages:0.1
  docker tag registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn:v1  newImages:0.1
  • 4.查看镜像创建历史:docker history 镜像
# 查看镜像registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn的创建历史
  docker history  registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn
  • 5.镜像归档: docker save 镜像
# 将镜像registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn保存成 sinn_v1.tar 归档文件
  docker save -o sinn_v1.tar registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn
  • 6.基于归档文件创建镜像:dokcer import 归档文件 新镜像tag
docker import sinn_v1.tar new_sinn:v2
3. 远程仓库镜像管理

命令如下:

  • 1.登陆远程镜像仓库:docker login 用户信息 仓库地址

如果未指定镜像仓库地址,则默认官方仓库Docker Hub

# 登录到官方Docker Hub仓库
docker login -u 用户名 -p 密码
# 登录到阿里云docker仓库
docker login --username=用户名  registry.cn-hangzhou.aliyuncs.com
  • 2.拉去镜像:docker pull 镜像
    docker pull registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn:v1
  • 3.推送镜像:docker push 镜像
    docker push registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn:v1
  • 4.搜索镜像:docker search 镜像
# 从官方Docker Hub仓库搜索node镜像
  docker search node
4. 镜像的使用

镜像通过docker run命令使用的, 这是关于容器部分的操作

# 指定使用registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn:v1镜像创建并启动容器
docker run --name  sinn-server -p 8080:8080 registry.cn-hangzhou.aliyuncs.com/sessionboy/sinn:v1

七. 容器的创建、启动和管理

创建容器的前提是要有镜像,有了镜像我们就可以创建和启动容器了。

1.容器的创建和启动

通过docker run命令即可实现容器的创建,并也会启动容器,这个命令实际上就包含了创建和启动容器两部分工作。

因此,容器的创建和启动是一体的。

下面说说docker run命令的用法。

docker run 命令的用法如下:

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
或
dokcer run 容器配置项 镜像 额外的配置

OPTIONS 是一些给容器添加的配置项,比如指定容器的名称,IP,是否后台启动等等。

IMAGE则表示镜像。COMMAND 则是一些额外的命令。

OPTIONS具体配置项如下:

-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
-d: 后台运行容器,并返回容器ID。也可以理解为守护进程运行。
-i: 以交互模式运行容器,通常与 -t 同时使用;
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
--name="nginx-lb": 为容器指定一个名称;
--dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
--dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-h "mars": 指定容器的hostname;
-e username="ritchie": 设置环境变量;
--env-file=[]: 从指定文件读入环境变量;
--cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;
-m :设置容器使用内存最大值;
--net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container四种类型;
--link=[]: 添加链接到另一个容器;
--expose=[]: 开放一个端口或一组端口;
--restart=no/on-failure/always  是否开机自动启动 ,no表示不启动,always表示始终启动,on-failure表示容器推出状态非0时重启
-v  标记来创建一个数据卷并挂载到容器里,实现宿主机目录或文件与指定的容器内目录或文件同步映射。

这么多配置项,除非有特殊需要,否则不必全部配置,使用docker默认的配置即可。但有些是经常使用或者必须的。比如:–name -d -v -e,这些是常用的配置项。

2. 容器的管理

docker 提供了很多关于容器的操作命令,包括删除容器,停止、启动容器等等。

下面列出一些常用的操作容器的命令

  • 1.查看容器:docker ps
    #列出所有正在运行的容器
    docker ps
  • 2.启动已经停止的容器:docker start
# 启动一个获取多个已经被停止的容器
  docker start [options] [containers]
  • 3.停止容器:docker stop
# 停止正在运行的容器 sinn-server
  docker stop sinn-server
  • 4.重启容器:docker restart
# 重启正在运行的容器 sinn-server
  docker restart sinn-server
  • 5.删除容器:docker rm
# 删除容器 sinn-server
  docker rm sinn-server
  • 6.杀掉正在运行的容器(包括进程):docker kill
# 杀掉容器 sinn-server
  docker kill sinn-server
  • 7.进入容器:docker exec

这个命令比较重要,因为通常我们需要进入容器去操作一些东西。

docker exec -it 容器名称/ID 终端
# 例子:进入ID为0d15561b9f10的容器
docker exec -it sinn-server bash
或
docker exec -it 0d15561b9f10 /bin/bash

注意:进入容器后,如果想退出容器,只需要输入exit命令执行即可。

  • 8.查看容器日志:dokcer logs
# 查看容器 sinn-server的日志
  docker logs sinn-server
  • 9.容器与主机之前数据拷贝:docker cp

往容器里拷贝数据,或从容器内拷贝数据出来,偶尔会常用到。

# 将主机的/data/user目录拷贝到容器sinn-server内的/data/user目录
docker cp /data/user sinn-server:/data/user
# 将容器sinn-server内的/data/user目录拷贝到主机的/data/user目录
docker cp sinn-server:/data/user /data/user

八.使用docker搭建数据库

以往我们搭建数据库或nginx服务的时候,通常需要手动去安装,然后做大量的配置。期间也经常会遇到各种各样的问题。

下来介绍一下,如何使用linux服务器用docker来快速搭建一个mongodb数据库。

1.首先拉去mongodb镜像
# 从docker官方仓库拉取mongo镜像(你也可以用第三方的mongo镜像,或自己创建的mongo镜像)
docker pull mongo
2.启动mongo容器

建立shell脚本“my-mongo.sh” 来运行mongodb容器启动命令

# my-mongo.sh
# 使用镜像"mongo"创建并启动容器"my-mongo"
docker run --name my-mongo -d -p 27017:27017 -v data/sinn-db:/data/db mongo
# -p 27017:27017    容器内27017端口与主机27017端口形成映射
# -d     守护进程运行
# --name my-mongo    指定容器名为my-mongo
# -v data/sinn-db:/data/db   将主机的"/data/sinn-db"目录挂载到容器内"/data/db"目录,作为mongodb数据存储目录

执行my-mongo.sh脚本即可
sh my-mongo.sh

容器启动成功后,mongodb已经启动。访问访问你IP的27017端口看到下面的提示,说明mongodb已经搭建成功。

It looks like you are trying to access MongoDB over HTTP on the native driver port.

使用docker搭建nginx也十分简单,只需要拉取nginx镜像,然后基于nginx镜像启动容器,启动时加一些nginx配置或指定nginx配置文件即可。

九. 总结

dokcer很强大,除了部署项目外,还可以用于搭建数据库,nginx服务等,它的用途十分广泛而且强大,另外它的性能消耗也很低,操作十分简单。

docker很容易学,它主要基于命令来操作,熟知这些命令以及Dockerfile脚本的配置,很快就能上手。