1. Docker简述
Docker利用虚拟化技术虚拟出应用程序的运行环境,使得应用程序得以运行。而主机仅需安装docker本身,并不需要再安装其它的环境。其好处如下:
- 可以在同一个主机上运行多个应用程序,而应用程序的运行环境彼此隔离,互不干扰
- 可以充分利用主机的计算和存储资源
- 新机器只需要安装docker并导入构建好的镜像就可以完成程序部署,免去了繁琐的安装和配置工作,维护成本大大降低
2. 单进程原则和运行环境最简原则
虽然在构建Docker镜像时理论上可以进行任意的安装和配置,但原则上构建Docker镜像应该仅为单个进程构建运行环境。假如一个web应用需要用到mysql服务器,则应该创建两个Docker镜像,一个用于运行tomcat服务器,一个用于运行mysql服务器。则运行tomcat的服务器镜像中仅需要tomcat的依赖环境,比如JDK。同理,mysql服务器镜像中则仅需安装mysql的依赖环境。这样做的好处是:
- 应用所运行的环境越简单,系统的稳定性越高
- 各个进程之间环境相互隔离,系统安全性高
- 便于镜像作为模块重用到多个系统中
3. Docker核心概念——镜像
所谓镜像就是程序运行的环境的只读版本。其包含了所有程序的依赖软件和配置。构建镜像的过程有些类似于在常规部署当中装系统、配环境的过程。注意,镜像是只读的,因此在构建镜像过程中不应该放入需要频繁修改的文件和配置。比如我们自行开发的应用程序可能需要不断的升级,则不适合放入镜像中。
3.1 镜像的分层
镜像是分层的。任何镜像都是基于一个基本镜像(如:linux某个版本的内核)逐步构建而成。镜像是只读的,在构建自定义镜像的过程中,每一步安装和配置都是在上一个镜像的基础上叠加一层形成新的镜像的过程。
3.2 获取基础镜像
可以从Docker Hub上下载自己需要的基础镜像,其中包含大量的官方镜像。具体使用方法可参照Docker命令一节。
4. Docker核心概念——容器
容器是镜像本身和叠加于镜像之上的一个读写层。应用程序仅能运行于容器之中。应用程序在容器中对系统所做的修改将仅体现在读写层,而并不会影响到其下面的镜像层。
值得注意的是,一个容器的存储空间是受限的。所以并不适合将应用程序的持久化功能放入容器当中。可以通过挂载外部路径的方式将持久化数据保存在容器以外。
5. Docker的工作模式
实际上Docker的工作模式非常简单。
- 一切以一个基础镜像开始
- 基于当前镜像,创建一个容器。
- 在该容器上执行一次部署操作后,固化为新的镜像
- 反复1、2步骤直到满足要求的镜像生成
- 在最终镜像上创建一个容器运行应用程序
6. Docker的安装方法
在ubuntu上安装Docker非常容易,仅需要执行如下命令
sudo apt-get install lxc-docker
7. Docker操作
注意,所有的Docker操作都需要root权限。所以在使用Docker前最好先进入root用户。
7.1 拉取镜像
首先,需要从Docker hub上拉取一个基础镜像。可在Docker hub官网上注册一个Docker hub账户,并搜索自己需要的基础镜像。并找到相应的image名称和tag名称。一个基础镜像是通过image名称+”:”+tag名称确定的。比如ubuntu:12.04,其中ubuntu为镜像名称,12.04代表镜像的tag。可执行如下命令从Docker hub上拉取一个基础镜像:
docker pull image名称:tag名称
其中image名称和tag名称分别代表具体的image和tag名称,中间用”:”分割。
7.2 编写Dockerfile并构建自定义image
接下来将基于基础镜像层层叠加,逐步构建为自定义的镜像。Dockerfile详细的描述了如何叠加镜像的每一层,最终形成自定义镜像。具体使用方法如下:
- 在任意位置创建目录,作为构建自定义镜像的工程目录
- 在目录中创建一个名字为Dockerfile的文本文件
- 编写Dockerfile
- 运行
docker build -t “image名称:tag名称” .
经过如上四步,就可以完成自定义镜像的构建了,下面详细说明如何编写Dockerfile。
7.2.1 编写Dockerfile
Dockerfile就是一个简单的文本文件,但需遵从Docker定义的语法格式编写,以便构建镜像的程序解析。Docker的语法格式非常简单。每一行代表一条命令,也就代表覆盖在基础镜像中的一层。一行命令的格式如下:
命令名称 命令参数
其中命令名称为大写英文字母,不同的命令名称有不同的命令参数。下面看一个Dockerfile的实例,实例取自Docker Hub上Mysql官方镜像。
FROM debian:jessie
RUN groupadd -r mysql && useradd -r -g mysql mysql
RUN mkdir /docker-entrypoint-initdb.d
RUN apt-get update && apt-get install -y perl pwgen --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys A4A9406876FCBD3C456770C88C718D3B5072E1F5
ENVMYSQL_MAJOR 5.7
ENVMYSQL_VERSION 5.7.10-1debian8
RUN echo "deb http://repo.mysql.com/apt/debian/ jessie mysql-${MYSQL_MAJOR
}" > /etc/apt/sources.list.d/mysql.list
RUN {
echo mysql-community-server mysql-community-server/data-dir select '';
echo mysql-community-server mysql-community-server/root-pass password '';
echo mysql-community-server mysql-community-server/re-root-pass password '';
echo mysql-community-server mysql-community-server/remove-test-db select false;
} | debconf-set-selections
&& apt-get update && apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/*
&& rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql
RUN sed -Ei 's/^(bind-address|log)/#&/' /etc/mysql/my.cnf
&& echo 'skip-host-cache\nskip-name-resolve' | awk '{ print } $1 == "[mysqld]" && c == 0 { c = 1; system("cat") }' /etc/mysql/my.cnf > /tmp/my.cnf
&& mv /tmp/my.cnf /etc/mysql/my.cnf
VOLUME /var/lib/mysql
COPY docker-entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
EXPOSE 3306
CMD ["mysqld"]
先不必搞明白该Dockerfile的全部含义。可以注意到,任何Dockerfile的第一行必须以FROM命令开头,来指定构建的基础镜像。然后,可以执行若干命令,最后通过ENTRYPOINT和EXPOSE命令指定使用该镜像的容器默认运行的命令和对外开放的端口号
注意,Dockerfile的没一行都相当于在上一行所构建的镜像中叠加了新的一层,形成一个新的镜像。在构建的过程中,Docker会缓存每一步获得的镜像结果。这样,若在构建过程中出现错误,可以从出错前一行构建的镜像继续构建,节省了调试Dockerfile的时间。
7.3 在镜像中创建容器
在镜像构建完成后,就可以在镜像中运行容器了。采用如下命令创建一个容器:
docker run -d --name "容器名称" 镜像名称:tag名称
由于使用了-d
命令,docker将以后台模式启动该容器。若想以命令行形式创建一个容器,则可以使用如下命令
docker run -i -t —-name "容器名称" 镜像名称:tag名称
当程序在容器中运行后,就可以在其它主机访问docker容器中的服务了。