Docker是为开发人员和系统管理员提供容器构建,运行和共享应用程序的平台。使用容器来部署应用程序称为容器化。容器不是新的,但用于轻松部署应用程序的容器却是新的。
yum install -y yum-utils device-mapper-persistent-data lvm2
Device Mapper 是 Linux2.6 内核中支持逻辑卷管理的通用设备映射机制,而device-mapper-persistent-data和lvm2是Device Mapper存储驱动程序必须要的工具:
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum clean all
yum makecache fast # 更新 yum 缓存
yum -y install docker-ce # 安装docker-ce
systemctl start docker
systemctl start docker.service
systemctl enable docker.service
接下来,我们通过Docker部署一个Tomcat容器。
docker pull tomcat
docker run -d --name first_tomcat -p 8080:8080 tomcat
docker exec -it containerid /bin/bash
运行tomcat容器之后,访问 http://192.168.216.129:8080 , 这个时候会提示400,找不到页面。
原因是用阿里云仓库中提供的tomcat镜像,默认的webapps的名字变成了webapps.dist,导致没有默认可以访问的页面,所以我们只需要进入到容器中修改一下就行。
在上面的案例中,执行 docker pull 去远程仓库拉去镜像时,会发现很慢,这是因为docker默认从hub.docker.com官方库中拉去镜像,这个是国外的网站访问起来比较慢,所以我们可以通过以下步骤将镜像源修改为阿里云:
1.登录阿里云,找到 产品与服务 -> 容器镜像服务 -> 镜像加速器 ,可以看到下图所示的aliyun镜像加速器地址。
2.执行 vim /etc/docker/daemon.json 下面命令,创建/修改文件,并设置加速器地址。
daemon.json:
{
"registry-mirrors": ["https://089rhvhq.mirror.aliyuncs.com"]
}
sudo systemctl daemon-reload
sudo systemctl restart docker
3.再次执行 docker pull tomcat , 就会发现下载速度快了很多
容器:是打包代码以及所有相关依赖项的软件标准单元,它可以使得应用从一个计算机环境快速可靠的移动到另外一个计算机环境去运行。
Docker:容器镜像是一个轻巧的、独立的、可执行的软件包,它包含了运行应用程序所需要的一切要素,如:代码、运行环境、系统工具、系统库以及环境。
容器和镜像的关系:简单来说可以这样去理解:一个软件包通过docker 构建之后成为一个image,而这个image在Docker Engine上运行时就变成了容器。每个容器都是相互隔离的,我们可以简单的把容器看作是一个建议版的Linux运行环境,Docker就是利用容器来运行应用的。
docker的镜像实际上是由一层一层的文件系统组成,这种层级的文件系统叫UnionFS(联合文件系统)。它是一种分层、轻量级并且高性能的文件系统,它支持文件系统的修改作为一次提交来一层一层的叠加。
前面官方资料讲过,Docker容器镜像包含了运行该应用程序所需要的一切因素,如代码、运行环境、系统工具、系统库,它的组成形态如下图所示:
需要注意的是,这些层都是只读,无法编辑。
其中,操作系统就是一个基础镜像,所谓的基础镜像就是没有父级镜像。
Linux得操作系统组成:内核空间、用户空间。
bootfs(不同的linux发行版本,bootfs基本上是一致的)
rootfs(不同的发行版本,用户空间的文件系统是不一样的)/dev /bin /etc /tmp
接下来,为了更好的说明镜像分层结构,我写一个Demo给大家看一下:
1.创建一个Dockerfile
## 指明当前要构建的镜像所继承的基础镜像
FROM java:8
## 设置工作目录
WORKDIR /app
## 把Hello.java拷贝到工作目录
COPY Hello.java /app
## docker镜像编译时出发的动作,它会在当前镜像上执行指定命令并形成一个新的层
RUN ["javac","Hello.java"]
## docker run执行时,会执行这个命令
ENTRYPOINT ["java","Hello"]
2.编写一个Hello.java,其中while循环是为了让容器不结束
public class Hello{
public static void main(String[] args){
System.out.println("Hello GupaoEdu.com");
while(true){
}
}
}
3.执行 docker build -t gupaoedu:hello-image . 具体的语法为 docker build [options] PATH|URL
首先FROM java:8表示当前镜像使用的基础镜像层,
然后执行RUN,执行RUN命令都是新建一个层,这一层用来编译Hello.java,而由于前面设置了WORKDIR,所以在构建镜像的每一层都会存在这个工作目录。
最终通过docker run运行,那么在镜像最上层会增加一个容器层,我们可以通过容器层来访问镜像。
这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如/etc 下的文件,这时其他容器的 /etc 是否也会被修改?答案是不会!
原因是对于镜像来说,它是只读的,也就是你无法去修改镜像。
那有同学又有疑问了,老师,你前面安装tomcat的时候,不是修改了tomcat这个镜像里面webapp目录吗?
实际上,容器的本质是镜像在运行的时候,在镜像最上层添加了一个可写层,我们所有的修改都是在这一层来完成的,而这个修改并不会对基础镜像产生影响,修改容器中的数据实际上是先从镜像层把数据复制到容器层,然后修改之后会把修改之后的数据保存在容器层,镜像层不会发生变化,这个其实就是UnionFS(联合文件系统)来实现的,所以它的影响只局限在当前的容器中。
UnionFS的一个最主要的应用是,把一张CD/DVD和一个硬盘目录给联合 mount在一起,然后,你就可以对这个只读的CD/DVD上的文件进行修改(当然,修改的文件存于硬盘上的目录里)。
所有对容器的改动,无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
下面我们深入讨论容器层的细节:
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
1.在spring-cloud-eureka-server项目的Dockerfile示例:
FROM openjdk:8
MAINTAINER [email protected]
LABEL name="gper-mall-eureka-server" version="1.0" author="Mic"
WORKDIR /gper/base
EXPOSE 9090
ADD ./spring-cloud-eureka-server-0.0.1-SNAPSHOT.jar ./gper-mall-eureka-server.jar
ENTRYPOINT ["java","-jar","gper-mall-eureka-server.jar"]
2.前提:程序不可运行,需要再pom里添加如下配置:
3.然后maven-package打包
4.复制Dockerfile文件和jar包到/data/docker/app文件夹
4.在 /data/docker/app中执行命令,生成镜像:
docker build -t gpermall:eureka-server .
5.查看打包出来的images:
docker images
6.运行docker
docker run --name eureka-server-9090 -p 9090:9090 gpermall:eureka-server
指定当前镜像的基础镜像,也就是当前新的镜像是在指定的基础镜像之上运行。
FROM ubuntu:14.04
在docker build期间执行命令,在build过程中,每一个RUN命令都会新建一个镜像层
shell:RUN <命令行命令> #与终端shell命令一样exec:RUNR ["可执行文件","参数1","参数2"]
RUN groupadd -r mysql && useradd -r -g mysql mysql
设置环境变量,可以通过${key}来引用,并且还可以通过 docker run --e key=value来设置环境变量的值.
将主机的文件复制到镜像内,如果目录不存在,会自动创建所需要的目录,注意只是复制,不会提取和解压。
ADD和COPY的作用类似,只是ADD会对压缩文件进行自动解压
指定镜像的工作目录,之后的命令都是基于此目录工作,若不存在则创建
容器启动的时候默认会执行的命令,若有多个CMD命令,则最后一个生效。
CMD ["mysqld"]
或
CMD mysqld
功能和CMD类似,但是和CMD不同的是,docker run执行的时候,可以在命令行参数中指定要运行的程序来覆盖Dockerfile中运行的指令。
而ENTRYPOINT不同,它无法通过docker run的命令行参数来覆盖ENTRYPOINT需要执行的指令,而且命令行中声明的数据会被当做参数传递给ENTRYPOINT指令指定的程序。
他们的相同点都是在docker运行的时候会默认触发执行的命令。
指定镜像要暴露的端口,启动镜像时,可以使用-p将该端口映射给宿主机。
EXPOSE 3306
拓展:
Docker学习笔记(6)——Docker Volume - 简书
你必须知道的Docker数据卷(Volume) - EdisonZhou - 博客园
docker volume - 简书