Docker 是一个使用 Go 语言开发的开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的机器上。Docker 的发展速度和火爆程度着实令人惊叹,一发不可收拾,形成了席卷整个IT界的新浪潮。
记得在公众号科普过 Docker 的一些基本概念,简单可以理解为集装箱,可以把你的程序、环境、配置等等全部装进去,这样在其他机器上达到开箱即用,也就是解决了环境不一致的问题。
还有就是每一个 Docker 都是相对隔离的,避免了资源使用上的一些问题。
Docker 的思想:标准化、集装箱、隔离,核心有镜像、仓库、容器等概念
Docker 是容器化技术的一个代表,这项技术并不是很新,在内核中很早之前就已经存在了,不过确实是因为 Docker 才火起来的,在云计算的领域,Docker 可谓是更加的火热,让程序猿和运维的关系更好了
Docker 你可以粗糙的理解为轻量级的虚拟机
走进Docker
下面来说说核心的三个词:镜像、仓库、容器;仓库就相当于码头,镜像就是集装箱,容器就是运行程序的地方,所以一般的使用步骤就是从仓库(码头)拉取镜像到本地,然后用命令把镜像运行起来。
相关的命令:Build(构建镜像)、ship(运输镜像)、run。
Docker 仓库的地址:hub.docker.com,如果速度慢,可以尝试国内的 c.163yun.com ,或者 daocloud 也不错。
如果我们的镜像比较私密,不想让别人知道,那么可以自己搭一个镜像仓库,就像 Maven 仓库哪样
PS:安装 Docker 推荐是在 ubuntu 上,因为本身就是在 ubuntu 上进行开发的,所以支持应该是最好的。
基本使用
下面介绍几个常用的命令:
- 从仓库拉取镜像:
docker pull name
- 查看本机的镜像:
docker images
- 运行镜像:
docker run name
如果需要在后台运行可以使用-d
参数
还可以加-e
指定用到的环境变量(用 MySQL 的时候可能会用到),指定多个环境变量可使用多次 -e;
一般情况,都是加个自定义的名字,这样:docker run --name myName -d mysql:latest
或者运行基础镜像:docker run --name mps -dit ubuntu
- 查看本机正在运行的容器:
docker ps
另外,它可以加个-a
参数来查看所有 - 进入容器:
docker exec -it [id] bash
id 由 run 命令(后台启动)返回,或者使用 ps 来查看,并且不需要输入完整,前几位就可以,与 git 比较类似。
然后就进入了这个容器,并且是以 bash 这个 shell 的方式,在容器中和 Linux 的操作基本一致,如同一个小型的 Linux 系统,并且是根据需求配置好的。
使用 exit 命令即可退出容器 - 停止容器:
docker stop id
,主要是对于那些后台启动的容器来说。
这里的停止并不是删除,区分下镜像和容器的关系。
所以,也可以使用docker start id
来启动容器。 - 重启容器:
docker restart id
- 删除镜像:
docker rmi id
注意和 rm 区分,一个是删除镜像,一个是删除容器。 - 清除运行过的镜像记录(缓存):
docker rm id
,可以使用docker ps -a
来查看记录
如果对命令参数不熟悉,可以查看帮助,如:docker run --help
;可以看出除了 pull 和 run 大部分命令都是依赖于镜像的 id 的;
一个镜像可以启动(run)多个容器,一个容器可以理解为一个虚拟环境。
如果我们需要将本机的某个文件放到容器里,有个快捷的命令:docker cp xxx.html [id]://usr/share/nginx/html
id 自然指的就是相应的容器了,不过你得熟悉你容器的文件分布情况才行,这种改动操作是临时的,当容器停止后改动不会被保存
如果需要永久保存,需要执行 commit 操作:docker commit -m "test" [id] name
这样就相当于是保存修改了,和 Git 是不是很像?它实际会根据改动生成一个新的镜像,所以要在最后指定新镜像的名字(版本也可以)
使用 docker tag xxx newName
可以实现镜像的复制….
想要 push 自己的镜像除了必要的账号,需要先进行登陆 docker login
,然后 docker push name
就可以了
Docker中的网络
Docker 会虚拟出一个运行环境,这个环境当然包括网络、文件等,也是通过 namespace 来进行区分,对于网络,虚拟有三种方式:
- Bridge
也就是我们所说的桥接,会虚拟出独立的一套网络配置(网卡),有独立的 ip、端口、iptab 规则等
这也是启动 Docker 的默认模式 - Host
使用物理机的网卡,和主机共用一套网络配置 - None
不配置网络,也就是容器内的程序不会与外界发生通讯
虚拟的方式是不是和配置虚拟机差不多呢~
在配置 Bridge 模式时,通常我们会配置端口映射,简单说就是当我们访问主机的某一个端口时,实际访问的是容器里的某一个端口,这个过程通过 Docker 提供的一个网桥实现(处理请求转发)
映射的配置可以在启动时就指定:docker run -d -p 8080:80 name
-p
后的第一个是本机的端口,第二个是对应的容器里的端口,上面的命令就实现了把本机 8080 的请求转发到容器的 80 端口上。
不放心的话可以使用 netstat -na|grep 8080
看看是不是处于监听的状态了。
另外一种就是使用 -P
的方式,是大写的 P,这种不需要再指定对应的端口,它会在本机开一些随机端口然后映射到容器里对应应用的端口上。
制作镜像
重头戏来了,如何把自己开发的程序打包成一个 Docker 应用呢,就像仓库里的那些一样。
用到的是 Dockerfile 和 build 命令,Dockerfile 可以理解为描述了打包流程,然后使用 build 会根据这个流程进行打包。
编写Dockerfile
是的,Dockerfile 只是一个文本文件,内容才是最重要的,可以直接使用 vim 来编写,名字就叫 Dockerfile,主要包括:
1 | 1.设置基础镜像(在某个镜像的基础上) |
上面是个简单的发布 Java 程序的环境,tomcat 的目录在那是从官网 tomcat 镜像说明页面找到的。
然后下面执行 docker build -t appName:latest .
来进行打包就可以了;-t 的作用是可以指定名字和版本,最后一个 .
表示当前目录。
然后使用 docker images
命令就可以找到我们自己发布的本地镜像了,运行和其他的一样
镜像分层
Docker 是分层存储的,在 Dockerfile 中一行就是一层,每一层都有它唯一的 ID。
这些层在 image (镜像)状态都是只读的(RO),当 image 运行为一个容器时,会产生一个容器层 (container layer),它是可读可写的(RW)。
分层的一个好处就是会减轻不少存储压力,多个 image 难免会有许多的相同的命令,分层后就可以实现共用。
存储
再来看看 Volume 吧,它提供独立于容器之外的持久化存储。
它就可以解决我们在容器内修改不会保存的问题,并且它可以提供容器与容器之间的共享数据
映射容器里的目录到本机
在运行时执行命令:docker run -d --name nginx -v /usr/share/nginx/html nginx
命令里的路径是容器里的地址,还给它起了个名字,运行后就会将配置的目录映射到本机(Host)的一个目录下,想要确定这个目录可以使用下面的命令查看容器信息:docker inspect nginx
后面跟的是我们起的那个名字哦,不是镜像名,然后重点看 Mounts 下的 Source 和 Destination 是不是正确,就是把容器内的 Destination 地址映射到了本机的 Source 目录下。
在本机的 Source 下修改会同步到容器里的 Destination 目录。
映射主机里的目录到容器
与上面正好相反,把本机的一个目录映射到容器里,命令:docker run -d -v $PWD/html:/usr/share/nginx/html nginx
这条命令就是把当前目录下的 html 文件夹映射到容器里 nginx 的目录下,这种方式用的比较多,非常的方便
建立只存数据的容器
这种情况或者说需求也是比较常见的,使用的命令是:docker create -v $PWD/data:/var/mydata --name data_container ubuntu
这样我们就创建了一个仅仅用来存储数据的新容器 data_container ,它会把当前目录下的 data 文件夹挂载到与之关联的容器的 /var/mydata
目录下,然后我们运行一个新的容器来测试下:docker run --volumes-from data_container ubuntu
volumes-from 的作用就是从另一个容器挂载,这样就实现了当前容器挂载仅有数据容器的目的,主要想体现的是这种仅有数据的容器可以被多个容器挂载使用,用来做数据的共享。
多容器APP
玩这个之前需要一个软件就是 docker-compose,在 Mac/Windows 下是自带的。
然后需要配置 docker-compose.yml 文件,文件名是固定的,使用的是 yaml 语法,也就是用缩进来表示层次关系,非常流行的一种配置文件格式。
Dockerfile 可以让用户管理一个单独的应用容器;
而 Compose 则允许用户在一个模板(YAML 格式)中定义一组相关联的应用容器(被称为一个 project,即项目),例如一个 Web 服务容器再加上后端的数据库服务容器等
最后写好 docker-compose 的配置文件后,就可以使用 docker-compose up -d
来运行了,停止就是 stop,rm 是删除;当重新修改配置文件后需要用 docker-compose build
重新来构建。
PS:在 docker-compose 配置的名字可以在其他的容器里直接用(比如 nginx 的配置文件里),不需要再配置解析。
关于 docker-compose 的使用这里不会多说,具体操作还是蛮复杂的,计划是等用到后再来补充,先暂且知道有这么个多容器的概念,可参考慕课网视频:https://www.imooc.com/video/15735
其他
有时我们需要合并两个镜像,但是这个功能并没有被提供,在 Dockerfile 中也不能使用多次 from,那么有什么好方法呢,可以使用命令先把镜像逆向出来,然后手动合并,镜像 –> Dockerfile 的命令:docker history --no-trunc=true image > image1-dockerfile
但是如果命令中有 ADD、COPY 之类的命令就会有一些问题,因为这些文件并不在你的机器上,需要自行处理了。
附:Dockerfile示例
一般是创建一个空目录,然后在这个空目录写 Dockerfile 文件,名字就叫 Dockerfile,这样打包的时候可以放心的用 .
:
1 | from ubuntu |
然后可以使用 curl http://localhost:80
来测试一下。
文件中没有用的其他关键字:ADD 也是添加文件,它比 COPY 更加强大,可以添加远程文件;CMD 也是执行命令的意思,可以用于指定容器的入口,也可以使用 ENTRYPOINT 命令
命令 | 用途 |
---|---|
WORKDIR | 指定路径 |
MAINTAINER | 维护者,现在推荐使用 LABEL maintainer |
ENV | 设定环境变量 |
ENTRYPOINT | 容器入口 |
USER | 指定用户 |
VOLUME | mount point(容器所挂载的卷) |
当没有指定 ENTRYPOINT 的时候,就用 CMD 来启动容器,如果指定了 ENTRYPOINT 那么 CMD 指定的字串就变成了 argus (参数)
关于DockerCompose
使用一个 Dockerfile 模板文件可以定义一个单独的应用容器,如果需要定义多个容器就需要服务编排。服务编排有很多种技术方案,Docker 官方产品是 Docker Compose 。
Dockerfile 可以让用户管理一个单独的应用容器;而 Compose 则允许用户在一个模板(YAML 格式)中定义一组相关联的应用容器(被称为一个 project,即项目),例如一个 Web 服务容器再加上后端的数据库服务容器等。
通过 Docker-Compose 用户可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。
Docker-Compose 解决了容器与容器之间如何管理编排的问题。
Compose 中有两个重要的概念:
- 服务 (service) :一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
- 项目 (project) :由一组关联的应用容器组成的一个完整业务单元,在
docker-compose.yml
文件中定义。
一个项目可以由多个服务(容器)关联而成,Compose 面向项目进行管理,通过子命令对项目中的一组容器进行便捷地生命周期管理。
Compose 项目由 Python 编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose 来进行编排管理。
安装:https://docs.docker.com/compose/install/
但是现在基本都是 K8S 的天下了,并且 K8S 支持将其转换为自己的配置文件。
拓展
https://yeasy.gitbooks.io/docker_practice/content/image/build.html
评论框加载失败,无法访问 Disqus
你可能需要魔法上网~~