走在通往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容器不需要额外的虚拟机管理软件和虚拟机操作系统层,直接在宿主机操作系统层面上实现虚拟化,从而达到轻量级,高效的目的。
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
:进行镜像创建的指令文件。
简单来说,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
镜像。 - 查看本地已有镜像、容器信息的
images
、inspect
和ps
命令。 - 删除本地镜像和容器的
rmi
和rm
命令。 - 基于已有容器创建镜像的
commit
命令和基于Dockerfile
创建镜像build
命令。 - 运行、进入容器的
run
、exec
和attach
命令。 - 镜像的保存和导入命令
save
和load
,容器的导出导入命令export
和import
具体命令的使用方法使用命令docker --help查看所有命令列表,使用docker COMMAND --help查看具体命令的信息
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
CMDCMD
命令有三种格式:
- CMD ["executable","param1","param2"]:推荐使用的 exec 形式。
- CMD ["param1","param2"]:无可执行程序形式
- CMD command param1 param2:shell 形式。
CMD
命令用于启动容器时默认执行的命令,CMD
命令可以包含可执行文件,也可以不包含可执行文件:不包含可执行文件的情况下就要用 ENTRYPOINT
指定一个,然后 CMD
命令的参数就会作为ENTRYPOINT
的参数。
一个
Dockerfile
中只能有一个CMD
,如果有多个,则最后一个生效。CMD
的shell
形式默认调用/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
,如果有多个,则最后一个生效。
关于 CMD
和 ENTRYPOINT
的联系请看下面的例子
仅仅使用 ENTRYPOINT
:
FROM ubuntu
ENTRYPOINT ls -l
docker build -t yumengzhong/lstest .
执行 docker run 306cd7e8408b /etc/fstab
和 docker 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
作为容器的入口,使用 CMD
给 ENTRYPOINT
增加默认选项:
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
EXPOSEEXPOSE <port> [<port>...]
命令用来指定对外开放的端口。
例如 EXPOSE 80 3306
,开放 80
和 3306
端口。
WORKDIRWORKDIR /path/to/work/dir
配合 RUN
,CMD
,ENTRYPOINT
命令设置当前工作路径。
可以设置多次,如果是相对路径,则相对前一个 WORKDIR
命令。默认路径为/
。
例如:
FROM ubuntu
WORKDIR /etc
WORKDIR ..
WORKDIR usr
WORKDIR lib
ENTRYPOINT pwd
docker run ID
得到的结果为:/usr/lib
USERUSER <UID/Username>
为容器内指定 CMD
、RUN
、ENTRYPOINT
命令运行时的用户名或UID
。
VLOUMEVOLUME ['/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)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。