Docker要点概览
一、Docker背景
Docker 从传统虚拟化方式进化而来,Docker是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现,这样做的好处多多:1、更快速的交付和部署,2、高效的部署和扩容,3、更高的资源利用率,4、更简单的管理。提高资源利用率、高效部署和扩容这些优点是相对于运维来说(尤其是大公司整体而言节省了许多机器资源),从开发角度来看,最主要的好处可能还是在隔离强、移植快!
- 隔离强:可以将应用程序打包封装到一个容器中,该容器包含了应用程序的代码、运行环境、依赖库、配置文件等必需的资源。容器之间达到进程级别的隔离,在容器中的操作,不会影响道宿主机和其他容器,服务之间不会相互影响!
- 移植快:用docker容器后,可以实现开发、测试和生产环境的统一化和标准化;打包好的容器移也可以移植到物理机、虚拟机、公有云、私有云、个人电脑、服务器等各种环境。尤其在各种中间件、DB上部署上,利用现有的标准化镜像进行快速的环境搭建。
但是有些特性比如启动快是伪命题,且对于传统应用来说,使用和不使用Docker可能并不能直接给企业带来好处,VM虚拟机其实够用但使用中遇到了问题肯定会更麻烦,因此在采用容器花技术时需要根据场景来权衡利弊。
source:微服务为什么要用docker
二、Docker的架构及核心组件
Docker 采用的是 Client/Server 架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。客户端和服务器可以运行在同一个 Host 上,客户端也可以通过 socket 或 REST API 与远程的服务器通信
Docker架构Docker 客户端 - Client:最常用的 Docker 客户端是 docker 命令。通过 docker 我们可以方便地在 Host 上构建和运行容器。
Docker 服务器 - Docker daemon:Docker daemon 是服务器组件,以 Linux 后台服务的方式运行。Docker daemon 运行在 Docker host 上,负责创建、运行、监控容器,构建、存储镜像。
Docker 镜像 - Image:具体的运行应用程序的一个进程,它里面包含应用程序的各种依赖。
Docker 容器 - Container:创建容器的模板,根据不同配置的镜像来创建不同的容器使用。镜像和容器的关系可以理解为面向对象中类和实例对象的关系。
Registry仓库:一个镜像只可以创建一种类型的容器,镜像多了就需要放到镜像仓库中存起来,仓库有本地镜像仓库和公共镜像仓库,平时使用本地仓库的镜像,没有的话去Registry hub公共镜像仓库下载。
三、Docker操作
1、首先第一步是在Linux系统上安装好docker的环境,网上都有不错的教程:
菜鸟:http://www.runoob.com/docker/centos-docker-install.html
博客:https://www.cnblogs.com/yufeng218/p/8370670.html
2、启动一个容器,可以从一个Http服务器开始:
# 1.启动容器 -d后台启动,-p映射端口
docker run -d -p 80:80 httpd
# 2.查看本地容器
docker images
# 3查看运行容器
docker ps -a
3、创建镜像
Dockerfile是一个文本文件,记录了镜像构建的所有步骤。-t
将新镜像命名为 ubuntu-with-vi-dockerfile,命令末尾的.
指明 build context 为当前目录。
# 1.Dockerfile形式创建
docker build -t ubuntu-with-vi-dockerfile .
# 2.会显示镜像的构建历史,也就是 Dockerfile 的执行过程。
docker history
Dockerfile的镜像创建并不是一帆风顺,出了错误需要进行调试可以参考:https://www.cnblogs.com/CloudMan6/p/6853329.html
Dockerfile的语法也可以参考:
https://www.cnblogs.com/CloudMan6/p/6864000.html
附上一则Nginx的Dockerfile创建实例,重要的命令基本都包含在内了:
# 拉取基础镜像
FROM centos
# 声明作者
MAINTAINER author
# 复制源文件到镜像空间中,tar包会自动解压
ADD nginx-1.13.2.tar.gz /usr/local/src
# 在容器中运行指定的命令。
RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel
RUN yum install -y libxslt-devel -y gd gd-devel GeoIP GeoIP-devel pcre pcre-devel
RUN useradd -M -s /sbin/nologin nginx
# 设置镜像中的当前工作目录,后续的run、cmd命令都在此目录中
WORKDIR /usr/local/src/nginx-1.13.2
# 编译nginx
RUN ./configure --user=nginx --group=nginx
--prefix=/usr/local/nginx --with-file-aio
--with-http_ssl_module --with-http_realip_module --with-http_addition_module
--with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module
--with-http_sub_module --with-http_dav_module --with-http_flv_module
--with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module
--with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module
--with-http_degradation_module --with-http_stub_status_module && make && make install
EXPOSE 80
4、镜像命名的规约:
一个特定镜像的名字由两部分组成:repository 和 tag,[image name] = [repository]:[tag]
如果执行 docker build 时没有指定 tag,会使用默认值 latest。其效果相当于:
docker build -t ubuntu-with-vi:latest
可以使用 docker tag 命令进行打包,如:docker tag myimage-v1.9.1 myimage:1
5、镜像仓库
首先可以使用Docker官方仓库,但是Docker Hub虽然非常方便,但还是有些限制,解决方案就是搭建本地的 Registry。Docker 已经将 Registry 开源了,同时在 Docker Hub 上也有官方的镜像 registry。
-
pull
从 registry 下载镜像
# repository的完整格式为:[registry-host]:[port]/[username]/image-name
docker push registry.example:5000/hello-world
-
push
将 镜像 上传到 registry -
docker rmi
删除 Docker host 中的镜像/docker rm
删除容器 -
docker search
搜索 Docker Hub 中的镜像
6、查看日志
通过docker exec
进入容器查看日志,-it
以交互模式,执行exit
退出容器,回到 docker host。
docker exec -it 'image-id' bash
所有容器的生命周期和状态整理如下:
https://www.cnblogs.com/CloudMan6/p/6961665.html
四、Docker镜像原理
1.base镜像
base 镜像有两层含义:
- 不依赖其他镜像,从 scratch 构建(白手起家从 0 开始构建)。
- 其他镜像可以之为基础进行扩展。
base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。Linux 操作系统由内核空间和用户空间组成,其中内核空间是kernel,用户空间的文件系统是 rootfs,包含我们熟悉的 /dev, /proc, /bin 等目录。对于base镜像来说,底层直接用Host的 kernel,自己只需要提供rootfs就行了。
Linux OS2. 镜像分层结构
新镜像是从base镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层,这样做的好处就是可:共享资源!当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
镜像分层结构Copy on Write机制:
- 添加文件:在容器中创建文件时,新文件被添加到容器层中。
- 读取文件:在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。
- 修改文件:在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。
- 删除文件:在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。
容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。Docker 会缓存已有镜像的镜像层,构建新镜像时,如果某镜像层已经存在,就直接使用,无需重新创建。Dockerfile 中每一个指令都会创建一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。
3.Docker存储
Data Volume上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中,一般来说应用服务可以放到容器中,因为这部分内容是无状态的,应该作为镜像的一部分。需要持久化的数据放在 Data Volume 中,并且需要和镜像分开存放。分为两种绑定挂载bind mount
和容器管理卷docker managed volume
,差别就在是否指定mount源。
# 数据挂载 -v 的格式为 <host path>:<container path>
docker run -d -p 80:80 -v <host path>:<container path> httpd
如果不指定mounts源,容器申请挂载docker manged volume
时,docker 都会在/var/lib/docker/volumes
下生成一个目录
docker inspect
查看 volume,我们也可以用 docker volume
命令:
关于bind mount
和docker managed volume
的差别可以参考(docker managed volume)这篇文章
- bind mount 是直接将要共享的目录 mount 到容器。
- docker managed volume 就要麻烦点。由于 volume 位于 host 中的目录,是在容器启动时才生成,所以需要将共享数据拷贝到 volume 中。