4

走在通往docker的大道上——docker基础知识汇总

最后编辑时间:2017年03月09日


1.Docker是什么

Docker是一种新的容器化技术,为应用开发和部署提供“一站式”容器解决方案,能帮助开发者高效快速的构建应用,实现“Build,Ship and Run Any App, Anywhere”,从而达到“一次构建,到处运行”的目的。

2.为什么Docker

相信大家都有这样的遭遇,每次要开发新软件或者换环境的时候,需要安装配置一大堆的依赖。虽然有yum或者apt这类的包管理软件帮忙,但是如果出现的包冲突,或者找不到包的情况,或者需要源码编译却缺失依赖,这种环境部署简直就是噩梦。

Docker就是解决上述噩梦的利器。同时,Docker也解决了跨平台部署的问题,你可以在MacOS, Windows, Linux上安装Docker,然后下载你所需要的Docker镜像(image)进行程序开发。当你的程序需要发布的时候,仅仅需要将你的Docker镜像打包发布,不再需要搭建新环境,让软件开发流程变得快速简单。

3.Docker的特色

包括但不仅限于:

  • 物美价廉
  • 轻量级和便携化
  • 低CPU 和内存使用
  • 启动、运行、关闭速度快
  • 可以用来作为云计算的基础

对于开发和部署来说,Docker可以:

  • 更快速的交付和部署应用环境
  • 更高效的资源利用率
  • 更便捷的迁移和扩展性
  • 更便捷的应用更新管理

4.Docker与虚拟机

Docker和虚拟机都是基于软件的平台虚拟化技术,其中:

  • 虚拟机属于完全虚拟化,即模拟完整的底层硬件环境特权指令的执行,客户操作系统无需进行修改。比如我们常用的VirtualBox,VMWare Workstation和Parallels Desktop等虚拟化软件。
  • Docker和其它容器技术便是操作系统级虚拟化,即直接通过内核创建虚拟的操作系统实例(内核和库),来隔离不同的进程和资源。

也就是说,Docker容器不需要额外的虚拟机管理软件和虚拟机操作系统层,直接在宿主机操作系统层面上实现虚拟化,从而达到轻量级,高效的目的。

clipboard.png

5.Docker核心概念

Docker底层组成:

  • Namespace:隔离技术的第一层,确保 Docker 容器内的进程看不到也影响不到 Docker 外部的进程。
  • Control Groups:LXC 技术的关键组件,用于进行运行时的资源限制。
  • UnionFS(文件系统):容器的构件块,创建抽象层,从而实现 Docker 的轻量级和运行快速的特性。

Docker的主要构成:

  • Docker Client:用户和 Docker 守护进程进行通信的接口,也就是 docker 命令。
  • Docker Daemon:宿主机上用于用户应答用户请求的服务。
  • Registry:注册服务器,注册服务器是存放仓库(Repository)的具体服务器。

Docker的三元素:

  • Container:用于运行应用程序的容器,包含操作系统、用户文件和元数据,相当于镜像Images的一个运行实例。。
  • Images:只读的 Docker 容器模板,简言之就是系统镜像文件。
  • DockerFile:进行镜像创建的指令文件。

clipboard.png

简单来说,Docker 镜像就是一个只读的模板。例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。

6.Docker安装

Docker是建立在Linux内核基础上的,在目前的主流Linux系统中,都已经原生支持了Docker且使用体验也最好,当然,在Windows平台和MacOS系统中也支持Docker,只是需要使用类似Boot2Docker等虚拟化工具来提供Linux支持。

关于在各种平台上安装Docker的方法参考 官网 的Docker Docs,这里不再赘述。

7.Docker基础命令

Docker提供了很多命令来管理镜像、容器和仓库。包括:

  • 从Docker Hub仓库中查找search、上传push、下载pull镜像。
  • 查看本地已有镜像、容器信息的imagesinspectps命令。
  • 删除本地镜像和容器的rmirm命令。
  • 基于已有容器创建镜像的commit命令和基于Dockerfile创建镜像build命令。
  • 运行、进入容器的runexecattach命令。
  • 镜像的保存和导入命令saveload,容器的导出导入命令exportimport

具体命令的使用方法使用命令docker --help查看所有命令列表,使用docker COMMAND --help查看具体命令的信息

clipboard.png

8.基础命令详解

1.检查安装 docker info

如果 Docker 没有安装,会提示command not found,如果 Docker 已经成功安装,则会有类似如下的提示:

输入
docker info

输出
Containers: 2
Images: 2
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 6
 Dirperm1 Supported: false
Execution Driver: native-0.2
Kernel Version: 3.13.0-24-generic
Operating System: Ubuntu 14.04 LTS
CPUs: 1
Total Memory: 979.6 MiB
Name: ubuntu
ID: PRLX:CY3O:TZ6P:4UAS:VDWM:MHWB:FB3V:TJBJ:GQ4J:Q453:GPOY:WZSI
WARNING: No swap limit support

2. 查看本地镜像 docker images

镜像是Docker生命周期中的“构建”部分,可以用来创建 Docker 容器。

输入 
docker images

输出
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
hello-world         latest              91c95931e552        5 days ago          910 B

3. 下载镜像 docker pull <image name>

输入
docker pull busybox

输出
latest: Pulling from busybox
cf2616975b4a: Pull complete
6ce2e90b0bc7: Pull complete
8c2e06607696: Already exists
busybox:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.
Digest: sha256:38a203e1986cf79639cfb9b2e1d6e773de84002feea2d4eb006b52004ee8502d
Status: Downloaded newer image for busybox:latest

busybox 是一个 Linux 工具集,包括各种常用命令,例如 cat、echo ,也有各种高级命令,例如 grep、mount 等。执行完 docker pull busybox 之后,Docker 会自动从 Docker 官方下载 busybox 的镜像文件。

这个过程中可以执行 Ctrl+C,docker pull 不会因为 Ctrl+C 打断,而回转为后台执行。

4. 运行镜像 docker run <image name>

输入 
docker run busybox /bin/echo Hello Docker

输出
Hello Docker

这条命令是运行 busybox 镜像中的 /bin/echo 命令,参数是 Hello Docker

其他标志:

-i 保证容器的stdin开启
-t 为容器生成一个tty终端
-d 表示后台运行
--rm=true 容器终止后删除
--name name 表示 container 的名称
-v 将目录挂载到 container
--privileged=true 防止没有权限访问挂载的目录
-p 9998:80 指定端口映射
--link name:container 与其他 container 链接.
--icc=true 去除 container 之间不互通. 需要放在 run 前面.

注意,--rm 和 -d 参数不能同时使用。

5.删除镜像 docker rmi

docker rmi <ID>/<name>

删除所有未打 tag 的镜像

docker rmi $(docker images -q | awk '/^<none>/ { print $3 }')

删除所有镜像

docker rmi $(docker images -q)

6. 查看本地容器 docker ps

docker ps 查看正在运行的容器

输入 
docker ps

输出
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
hello-world         latest              91c95931e552        1 days ago          910 B

docker ps -a 查看所有的容器,-q 返回 id

docker ps -a -q

docker ps -n x 该命令会显示最后x个容器,不论这些容器是运行还是停止的。

7. 查询输出docker logs <ID>/<name>

查询容器的输出内容:

例如:通过 docker logs 命令查询 sample_job 对应的容器的输出内容。

sample_job=$(docker run -d busybox /bin/sh -c "while true; do echo Docker; sleep 1; done")
输入 
docker logs $sample_job

输出
Docker
Docker
Docker
Docker

只要这个容器运行的时间足够长,就会输出足够多行的 Docker。

8. 启动容器docker start

docker start <ID>/<name>

9. 停止容器docker stop

docker stop <ID>/<name>

10. 重启容器docker restart

docker restart <ID>/<name>

11.删除容器 docker rm

docker rm <ID>/<name>

删除所有 Docker 容器

docker rm $(docker ps -a -q)

12.保存容器docker commit

docker commit -m='A new image' --author='Aomine' 614122c0aabb aoct/apache2

将当前的 Docker 容器保存为一个名为 aoct/apache2 的镜像。-m指定创建镜像的提交信息,--author指定镜像作者,接着是容器ID、目标镜像仓库、镜像名。

13. 镜像上传docker push

创建docker hub账户,将本地的image push 到hub上,这样其他人也可以使用了。首先我们先tag 一个image,然后将其push到我们的repo里。

docker tag id {username}/{images_name}:v1
docker push {username}/{images_name}

14. 获取镜像历史docker history

docker history <image-name>

只能对本地存在的 Docker 镜像执行这个命令。

15.进入容器

当我们使用 -d参数运行了一个Container的时候,有时候我们需要进入这个容器进行一些操作。例如有这样的一个情况,我们运行了一个app在一个容器里,我们想进入容器看看,这个app运行的状态,查看log。那们如何进入呢?其实有很多种方法,这里介绍两种。

1.docker attach <ID>/<name>
$ docker run -d --name demo ubuntu /usr/bin/top -b
$ docker attach demo
2.docker exec <ID>/<name>
    docker exec -i -t webapp /bin/bash

docker attach 和 docker exec区别

docker attach让用户可以进入Container查看输出等等操作,但是并不会另外启动一个进程! 如果你用CTRL-c来退出,同时这个信号会kill Container(默认情况)

docker exec 会启动另外一个进程来进入Container,这里的操作是在这个进程下的。如果你用CTRL-c来退出,不会kill 原来的Container

16.镜像的导入与导出load & save

使用 load 从 stdin 导入一个 tar 格式的镜像或者仓库,然后用 save 将 tar 镜像输出到 stdout。

docker save -o <output file> <image>或者docker save <image> > <output file>
docker load -i <file name>或者docker load < <file name>

这两个命令常用于多节点部署。

例如:

命令 # docker save -o a.tar suse
命令 # docker load -i a.tar

17.容器导入import

用于导入 URL / 文件,从本地导入需要 - 参数。docker import [OPTIONS] URL|- [REPOSITORY[:TAG]]、URL/-二选一。

命令# docker import http://mirrors.ustc.edu.cn/openvz/template/precreated/suse-13.1-x86-minimal.tar.gz suse:minimal  #这里使用的是ustc镜像源。
Downloading from http://mirrors.ustc.edu.cn/openvz/template/precreated/suse-13.1-x86-minimal.tar.gz
127a9e7b9f87e4fc280c96bee9fad0a19057de38d307fe7fc1f6d35c86f1aff657.89 MB/57.89 MB
命令# docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
suse                     minimal             127a9e7b9f87        2 minutes ago       149.1 MB

导入本地镜像:

cat suse-13.1-x86-minimal.tar.gz |docker import - suse:minmal

18.容器导出export

和 import 相反,export 将容器导出成 tar 压缩包。

例如

命令 # docker run -i -t -d suse:minimal /bin/bash
060f6e6c877af01313363b6506107438b9eb5ba87a7ef0625577e348a554ecca
命令 # docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
060f6e6c877a        suse:minimal        "/bin/bash"         2 seconds ago       Up 2 seconds                            fervent_ritchie
命令 # docker export -o a.tar 060f
命令 # docker export 060f > a.tar  #也可以这样。

9.什么是Dockerfile

Dockerfile实际上是由一行行命令组成的,让用户可以方便的创建自定义镜像。

Dockerfile大体由四部分组成:

  • 指明基础镜像指令FROM
  • 维护者信息指令MAINTAINER
  • 镜像操作指令RUN、EVN、ADD和WORKDIR等
  • 容器启动时的执行指令CMD、ENTRYPOINT和USER等

下边就是一个Dockerfile的例子

FROM python:2.7
MAINTAINER yumengzhong <760042201@qq.com>
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
EXPOSE 5000
ENTRYPOINT ["python"]
CMD ["app.py"]
 1. 从dockerhub上pull下python 2.7的基础镜像。
 2. 维护者的信息
 3. copy当前目录到容器中的 /app目录下  复制本地主机的<src>(Dockerfile所在目录的相对路径)到容器里<dest>
 4. 指定工作路径为/app
 5. 安装依赖
 6. 暴露5000端口
 7. 启动app

这个例子是启动一个python flask app的Dockerfile(flask是python的一个轻量的web框架)。

下边我就来介绍下dockerfile里常用的指令。

格式
Dockerfile 中所有的命令都是以下格式:INSTRUCTION argument
指令(INSTRUCTION)不分大小写,但是推荐大写。

FROM
用于指定基础的images

格式为 FROM <image> or FORM <image>:<tag>

所有的 Dockerfile 都用该以 FROM 开头,FROM 命令指明 Dockerfile 所创建的镜像文件以什么镜像为基础,FROM 以后的所有指令都会在 FROM 的基础上进行创建镜像;可以在同一个 Dockerfile 中多次使用 FROM 命令用于创建多个镜像。

MAINTAINER
格式为 MAINTAINER <name> 用于指定镜像创建者和联系方式。

MAINTAINER yumengzhong <760042201@qq.com>

RUN
格式为 RUN <command>
用于容器内部执行命令。每个 RUN 命令相当于在原有的镜像基础上添加了一个改动层,原有的镜像不会有变化。

ADD
格式为 ADD<src><dest> 将主机文件复制到容器中

该命令将复制指定的 <src> 到容器中的 <dest>。其中 <src> 可以是Dockerfile所在目录的一个相对路径,可以是文件或目录的路径,也可以是一个URL,还可以是一个 tar 文件(自动解压为目录)。

ADD /path/to/sourcefile/in/host /path/to/targetfile/in/container

COPY
格式为 COPY <src><dest>

复制本地主机的 <src>(为 Dockerfile 所在目录的相对路径)到容器中的 <dest>

当使用本地目录为源目录时,推荐使用 COPY

CMD
CMD 命令有三种格式:

  • CMD ["executable","param1","param2"]:推荐使用的 exec 形式。
  • CMD ["param1","param2"]:无可执行程序形式
  • CMD command param1 param2:shell 形式。

CMD 命令用于启动容器时默认执行的命令,CMD 命令可以包含可执行文件,也可以不包含可执行文件:不包含可执行文件的情况下就要用 ENTRYPOINT 指定一个,然后 CMD 命令的参数就会作为ENTRYPOINT的参数。

一个 Dockerfile 中只能有一个CMD,如果有多个,则最后一个生效。
CMDshell 形式默认调用 /bin/sh -c 执行命令。
CMD 命令会被 Docker 命令行传入的参数覆盖:docker run busybox /bin/echo Hello Docker 会把 CMD 里的命令覆盖。

ENTRYPOINT

ENTRYPOINT 命令也有两种格式:

  • ENTRYPOINT ["executable", "param1", "param2"] :推荐使用的 exec 形式
  • ENTRYPOINT command param1 param2 :shell 形式

ENTRYPOINT 命令的字面意思是进入点,而功能也恰如其意:他可以让你的容器表现得像一个可执行程序一样。
一个 Dockerfile 中只能有一个 ENTRYPOINT,如果有多个,则最后一个生效。

关于 CMDENTRYPOINT 的联系请看下面的例子

仅仅使用 ENTRYPOINT

FROM ubuntu
ENTRYPOINT ls -l
 docker build -t yumengzhong/lstest .

执行 docker run 306cd7e8408b /etc/fstabdocker run 306cd7e8408b 结果并不会有什么差别:

命令 # docker run 306cd7e8408b /etc/fstab
total 64
drwxr-xr-x   2 root root 4096 Mar 20 05:22 bin
drwxr-xr-x   2 root root 4096 Apr 10  2014 boot
drwxr-xr-x   5 root root  360 Apr 24 02:52 dev
drwxr-xr-x  64 root root 4096 Apr 24 02:52 etc
drwxr-xr-x   2 root root 4096 Apr 10  2014 home
……

但是我们通常使用 ENTRYPOINT 作为容器的入口,使用 CMDENTRYPOINT 增加默认选项

FROM ubuntu
CMD ["-l"]
ENTRYPOINT ["ls"]

然后执行这个容器:
不加参数便会默认有 -l参数:

命令 # docker run 89dc7e6d0ac1
total 64
drwxr-xr-x   2 root root 4096 Mar 20 05:22 bin
drwxr-xr-x   2 root root 4096 Apr 10  2014 boot
drwxr-xr-x   5 root root  360 Apr 24 02:47 dev
drwxr-xr-x  64 root root 4096 Apr 24 02:47 etc
drwxr-xr-x   2 root root 4096 Apr 10  2014 home
drwxr-xr-x  12 root root 4096 Mar 20 05:21 lib
drwxr-xr-x   2 root root 4096 Mar 20 05:20 lib64
drwxr-xr-x   2 root root 4096 Mar 20 05:19 media
drwxr-xr-x   2 root root 4096 Apr 10  2014 mnt
drwxr-xr-x   2 root root 4096 Mar 20 05:19 opt
dr-xr-xr-x 386 root root    0 Apr 24 02:47 proc
drwx------   2 root root 4096 Mar 20 05:22 root
drwxr-xr-x   7 root root 4096 Mar 20 05:21 run
drwxr-xr-x   2 root root 4096 Apr 21 22:18 sbin
drwxr-xr-x   2 root root 4096 Mar 20 05:19 srv
dr-xr-xr-x  13 root root    0 Apr 24 02:47 sys
drwxrwxrwt   2 root root 4096 Mar 20 05:22 tmp
drwxr-xr-x  11 root root 4096 Apr 21 22:18 usr
drwxr-xr-x  12 root root 4096 Apr 21 22:18 var

加了 /etc/fstab 参数便会覆盖原有的 -l 参数:

命令 # docker run 89dc7e6d0ac1 /etc/fstab
/etc/fstab

EXPOSE
EXPOSE <port> [<port>...] 命令用来指定对外开放的端口。
例如 EXPOSE 80 3306,开放 803306 端口。

WORKDIR
WORKDIR /path/to/work/dir 配合 RUNCMDENTRYPOINT 命令设置当前工作路径。
可以设置多次,如果是相对路径,则相对前一个 WORKDIR 命令。默认路径为/

例如:

FROM ubuntu
WORKDIR /etc
WORKDIR ..
WORKDIR usr
WORKDIR lib
ENTRYPOINT pwd

docker run ID 得到的结果为:/usr/lib

USER
USER <UID/Username> 为容器内指定 CMDRUNENTRYPOINT 命令运行时的用户名或UID

VLOUME
VOLUME ['/data'] 允许容器访问容器的目录、允许容器之间互相访问目录。
VOLUME 仅仅是允许将某一个目录暴露在外面,更多的操作还需要依赖 Docker 命令实现。

ENV
参考 export 的用法咧:
ENV LC_ALL en_US.UTF-8

10.构建dockerfile

Dockerfile 的写法已经讲述完毕,来看示例:

实例一

mkdir static_web
cd static_web
touch Dockerfile
然后 vi Dockerfile  开始编辑该文件
输入 i 开始编辑

FROM nginx
MAINTAINER yumengzhong "760042201@qq.com"
ENV REFRESHED_AT 2017-03-03
RUN echo '<h1>hello,<a href="http://www.imooc.com">慕课网</a>!</h1>' >  /usr/share/nginx/html/index.html

编辑完后 按 esc 退出编辑
然后  :wq    写入 退出

补充

:q! 强行退出(不存盘)
:wq 强制性写入文件并退出。即使文件没有被修改也强制写入,并更新文件的修改时间。
:x 写入文件并退出。仅当文件被修改时才写入,并更新文件修改时间,否则不会更新文件修改时间。
ESC键只能切换到命令状态

:x:wq 的真正区别
:wq 强制性写入文件并退出。即使文件没有被修改也强制写入,并更新文件的修改时间。
:x 写入文件并退出。仅当文件被修改时才写入,并更新文件修改时间,否则不会更新文件修改时间。

这两者一般情况下没什么不一样,但是在编程方面,对编辑源文件可能会产生重要影响。因为文件即使没有修改,:wq 强制更新文件的修改时间,这样会让 make 编译整个项目时以为文件被修改过了,然后就得重新编译链接生成可执行文件。这可能会产生让人误解的后果,当然也产生了不必要的系统资源花销。

docker build -t yumengzhong/nginx_web:v1 .

-t是为新镜像设置仓库和名称,其中yumengzhong为仓库名,nginx_web为镜像名,:v1为标签(不添加为默认latest)

docker run --name nginx_web -d -p 82:80 yumengzhong/nginx_web:v1

游览器 192.168.99.100:82或localhost:82

实例二

#Dockerfile
FROM centos6-base
#指定centos6系统
MAINTAINER zhou_mfk <zhou_mfk@163.com>
#我抄的他的 Dockerfile
RUN ssh-keygen -q -N "" -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -q -N "" -t rsa -f /etc/ssh/ssh_host_rsa_key
#创建私钥
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
#修复SSH登录,否则登陆后的用户会被秒退。
RUN mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh
#创建root用户的ssh文件夹
EXPOSE 22
#开放端口
RUN echo 'root:redhat' | chpasswd
#root用户改密码为redhat
RUN yum install -y yum-priorities && rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm && rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
RUN yum install tar gzip gcc vim wget screen -y
#安装epel和安装一些软件
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
#系统环境变量
CMD ["/usr/sbin/sshd", "-D"]
#启动sshd
#End

11.升级Docker

如果想升级到最新版的Docker,就用 apt-get

$ apt-get upgrade docker-engine

12.卸载Docker

$ apt-get purge docker-engine
$ apt-get autoremove # 自动删除依赖
$ rm -rf /var/lib/docker

参考&引用

1.Docker学习与和应用系列
2.Flux7 Docker 系列教程
3.Docker 实践系列
4.我的Docker笔记(补全ing)


于梦中2010
2.1k 声望181 粉丝

前端菜鸟儿,请多关照!