Docker容器技术——真的很细

目录

一、容器介绍

1、云计算服务类型

2、容器本质

3、容器和虚拟机对比

4、 docker基本概念

5、docker的优势

交付物标准化

一次构建,多次交付

应用隔离

6、Docker三大核心组件

Docker仓库

Docker容器

7、Docker对服务器端开发/部署带来的变化

二、容器安装部署

三、国内镜像仓库的使用

四、深入理解容器

1、docker的镜像和容器的区别

Docker镜像

Docker容器

2、容器名称

3、镜像名称

4、命名空间

pid名字空间

net名字空间

mnt名字空间

五、Docker的使用

1、镜像操作

2、容器操作

六、创建自己的镜像

1、将容器的文件系统打包成tar包

2、镜像迁移

3、通过容器创建本地镜像

七、通过dockerfile创建镜像

1、docker build语法:

常用选项说明

2、PATH|URL|- 说明

案例:使用Docker部署微服务项目

八、Docker-compose

1、docke-compose介绍

2、Docker安装

3、docker-compose安装

4、docker-compose文件结构和示例

docker-compose文件结构

docker-compose使用示例

6、compose常用服务配置参考

build


一、容器介绍

Docker容器技术——真的很细_第1张图片

容器其实是一种沙盒技术。顾名思义,沙盒就是能够像一个集装箱一样,把你的应用“装起来”的技术。河阳应用于应用之间,就因为有了边界而不至于相互干扰;而被装进集装箱的应用,也可以被方便的搬来搬去,这其实是PaaS最理想的状态。

1、云计算服务类型

基础设施级服务laas

平台级服务PaaS

软件级服务SaaS

2、容器本质

容器的本质是进程,容器就是未来云计算系统中的进程。容器镜像就是这个系统里的“.exe”安装包

3、容器和虚拟机对比

Docker容器技术——真的很细_第2张图片

 容器是应用程序的抽象,将代码和依赖项打包在一起。多个容器可以在同一台计算机上运行,并与其他容器共享OS内核,每个容器在用户空间中作为隔离的进程运行。容器占用的空间少于VM,可以处理更多的应用程序,并且需要的VM和操作系统更少。

特性

虚拟机

容器

启动

分钟级

秒级

硬盘启动

一般为GB

一般为MB

性能

弱于

接近原生

系统支持量

一般几十个

单机支持上千个容器

4、 docker基本概念

Docker系统有两个程序:docker服务端和docker客户端。

Docker服务端:

是一个服务进程,管理着所有的容器。

Docker客户端:

是docker服务器的远程控制器,可以用来控制docker的服务端进程。

5、docker的优势

交付物标准化

Docker是软件工程师领域的“标准化”交付组件,最恰到好处的类比是“集装箱”。

集装箱将零散、不易搬运的大量物品封装成一个整体,集装箱更重要的意义在于它提供了一种通用的封装货物的标准,卡车、火车、货轮、桥吊等榆树或搬运工具采用此标准,隧道、桥梁等也采用此标准。以集装箱为中心的标准化设计大大提高了物流体系的运行效率。

传统的软件交付物包括:应用程序、依赖软件安装包、配置说明文档、安装文档、上线文档等非标准化组件。

Docker的标准化交付物称为“镜像”,它包含了应用程序及其所依赖的运行环境,大大简化了应用交付的模式。

一次构建,多次交付

类十余集装箱的“一次装箱,多次运输”,Docker镜像可以做到“一次构建多次交付”。当涉及到应用程序多副本部署或者应用程序迁移时,更能体现、docker的价值。

应用隔离

集装箱可以有效做到货物之间的隔离,是化学物品和视频可以堆砌在一起运输。Docker可以隔离不同应用 程序之间的相互影响,但是比虚拟机开销更小。

总之,容器技术部署速度比较快,开发、测试更敏捷;提高系统利用率,降低资源成本。

namespace  空间隔离

cgroup    资源限制

rootfs     文件系统

6、Docker三大核心组件

Docker镜像-Docker images

Docker仓库-Docker registeries

Docker容器-Docker containers

Docker仓库

用来保存镜像,可以理解为代码控制中的代码仓库。同样的,Docker仓库也有公有和私有的概念。

公有的Docker仓库名字是Docker Hub。Docker Hub提供了庞大的镜像集合应用。这些镜像可以是自己创建,或者在别人的镜像基础上创建。Docker仓库是Docker的分发部分。

库:registry

公有库:

Docker-hub Daocloud  ali  网易蜂巢

私有库:

公司内部使用(自己部署)

分类:

操作系统名称 centos ubuntu

应用名称 nginx tomcat mysql

Tag:表示镜像版本

Docker镜像

Docker镜像是Docker容器运行时的只读模板,每一个镜像由一系列的层(layers)组成。

每一个镜像都可能依赖于由一个或多个下层的组成的另一个镜像。下层那个镜像是上层镜像的父镜像。

镜像名称:

仓库名称+镜像分类+tag名称(镜像版本)

例如:docker.io/nginx:v1

docker.io/nginx:latest

daocloud.io/centos:6

镜像id:64位的id号

基础镜像:一个没有父镜像的镜像,称为基础镜像。

 注意:Registry中镜像是通过Repository来组织的,而每个Repository又包含了若干个lmage。Registry包含一个或多个Repository。

Docker容器

Docker容器与文件夹很类似,一个docker容器包含了所有某个应用所需运行的环境。每一个Docker容器都是从Docker镜像创建的。Docker容器可以运行、开始、停止、移动和删除。每一个docker容器都是独立和安全的应用平台,Docker容器是Docker的运行部分。

7、Docker对服务器端开发/部署带来的变化

方便快速部署
对于部署来说可以极大的减少部署的时间成本和人力成本

Docker支持将应用打包进一个可以移植的容器中,重新定义了应用开发,测试,部署上线的过程,核心理念是 Build once, Run anywhere

1)标准化应用发布,docker容器包含了运行环境和可执行程序,可以跨平台和主机使用

2)节约时间,快速部署和启动,VM启动一般是分钟级,docker容器启动是秒级;
3)方便构建基于微服务架构的系统,通过服务编排,更好的松耦合;
4)节约成本,以前一个虚拟机至少需要几个G的磁盘空间,docker容器可以减少到MB级;

 Docker 优势:

1、交付物标准化
Docker的标准化交付物称为"镜像",它包含了应用程序及其所依赖的运行环境,大大简化了应用交付的模式。

2、应用隔离
Docker可以隔离不同应用程序之间的相互影响,但是比虚拟机开销更小。总之,容器技术部署速度快,开发、测试更敏捷;提高系统利用率,降低资源成本. 

3、一次构建,多次交付
类似于集装箱的"一次装箱,多次运输",Docker镜像可以做到"一次构建,多次交付"。

Docker的度量:

Docker是利用容器来实现的一种轻量级的虚拟技术,从而在保证隔离性的同时达到节省资源的目的。Docker的可移植性可以让它一次建立,到处运行。Docker的度量可以从以下四个方面进行:

1)隔离性

 通过内核的命名空间来实现的,将容器的进程、网络、消息、文件系统和主机名进行隔离。

2)可度量性

 Docker主要通过cgroups控制组来控制资源的度量和分配。

3)可移植性

 Docker利用AUFS来实现对容器的快速更新。

 AUFS是一种支持将不同目录挂载到同一个虚拟文件系统下的文件系统,支持对每个目录的读写权限管理。AUFS具有层的概念,每一次修改都是在已有的只写层进行增量修改,修改的内容将形成新的文件层,不影响原有的层。

4)安全性

 安全性可以分为容器内部之间的安全性;容器与托管主机之间的安全性。

 容器内部之间的安全性主要是通过命名空间和cgroups来保证的。

 容器与托管主机之间的安全性主要是通过内核能力机制的控制,可以防止Docker非法入侵托管主机。


Docker容器使用AUFS作为文件系统,有如下优势:

1)节省存储空间

 多个容器可以共享同一个基础镜像存储。

2)快速部署

3)升级方便
 升级一个基础镜像即可影响到所有基于它的容器。需要注意已经在运行的docker容器不受影响

容器和 VM 的主要区别:

表面区别:

容器占用体积小,虚拟机占用体积大

隔离性:容器提供了基于进程的隔离,而虚拟机提供了资源的完全隔离。

启动速度:虚拟机可能需要一分钟来启动,而容器只需要一秒钟或更短。

容器使用宿主操作系统的内核,而虚拟机使用独立的内核。Docker 的局限性之一是,它只能用在64位的操作系统上。

本质区别:容器是被隔离的进程 

二、容器安装部署

使用aliyun docker yum 安装新版docker

docker-ce社区版

docker-ee企业版

删除已安装的Docker(可选,如果之前没有docker的环境,可以不做)

yum -y remove docker \
     docker-client \
     docker-client-latest \
     docker-common \
     docker-latest \
     docker-latest-logrotate \
     docker-logrotate \
     docker-selinux \
     docker-engine-selinux \
     docker-engine

配置阿里云DockerYum源

[root@ansible ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 git
[root@ansible ~]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum list docker-ce --showduplicates
安装较旧版本(比如Docker17.03.2):
需要指定完整的rpm包包名,并且加上--setopt=obsoletes=0参数:
yum -y install --setopt=obsoletes=o \
docker-ce-17.03.2.ce-1.el7.centos.x86_64 \
docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch
安装Docker新版本(比如Docker19.03.0):
yum -y install docker-ce-19.03.0:
或者yum -y install docker-ce

启动Docker服务

systemctl start docker
systemctl enable docker

查看docker版本状态

[root@docker ~]# docker -v
Docker version 20.10.16, build aa7e41

查看docker运行状态

[root@docker ~]# docker info

三、国内镜像仓库的使用

国内镜像战:https://daocloud.io

国外镜像站:https://hub.docker.com

在使用国内镜像站之前需要注册一个daocloud或者docker官方镜像站的账号,这个账号可以,这个账号可以在网页登录,也可以在服务器上登录。

可以在发现镜像中搜索我们需要的镜像

Docker容器技术——真的很细_第3张图片

 可以在集群管理中查看我们的主机和容器,也可以对主机进行管理,添加主机等操作

Docker容器技术——真的很细_第4张图片

 点击添加主机后,根据我们的操作系统来添加一个主机,然后在服务器上执行安装主机监控程序Docker容器技术——真的很细_第5张图片

 执行完上述命令之后,等待显示接入成功,我们就能通过网页对我们的主机和容器进行管理

Docker容器技术——真的很细_第6张图片

 点击查看主机就能看到我们添加的主机

Docker容器技术——真的很细_第7张图片

 国内的daocloud镜像站为我们提供了一个功能,可以直接在网页上往我们的docker服务器上下载镜像并创建容器。

我们随便找一个镜像点进去

Docker容器技术——真的很细_第8张图片

 点击右上角的部署

Docker容器技术——真的很细_第9张图片

Docker容器技术——真的很细_第10张图片Docker容器技术——真的很细_第11张图片

 页面跳转之后可以看到这里在下载中

Docker容器技术——真的很细_第12张图片

看到运行中后我们可以访问宿主机ip加82端口验证一下 

Docker容器技术——真的很细_第13张图片

 可以看到访问82端口成功访问到nginx的默认网站发布页,是不是很方便Docker容器技术——真的很细_第14张图片

 镜像加速器

使用Docker的时候,需要经常从官方获取镜像,但是由于显而易见的网络原因,拉取镜像的过程非常耗时,严重影响使用docker的体验。因此,daocloud推出了加速器工具解决这个难题,通过智能路由和缓存机制,极大提升了国内网络访问Docker Hub的速度,目前已经拥有了广泛的用户群体,并得到了Docker官方的大力推荐。

Docker容器技术——真的很细_第15张图片

 点进去之后往下拉,将对应系统的命令在我们的docker上执行

Docker容器技术——真的很细_第16张图片

 登录登出docker hub或者daocloud.io

[root@ansible ~]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: 18737531136
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

[root@ansible ~]# docker login daocloud.io
Username: cloud_2201
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

退出登录

[root@ansible ~]# docker logout
Removing login credentials for https://index.docker.io/v1/

四、深入理解容器

1、docker的镜像和容器的区别

Docker镜像

假设Liunx内核是第0层,那么无论怎么运行Docker。他都是运行于内核层之上的。这个docker镜像,是一个只读镜像,位于第1层,他不能被修改或不能保存状态。

一个docker镜像可以构与另一个docker镜像之上,这种层叠关系可以是多层的。第一层的镜像我们称之为基础镜像(Base lmage),其他层的镜像(除了最顶层)我们称之为父层镜像(Parent lmage)。这些镜像继承了他们的父层镜像的所有属性和设置,并在dockerfile中添加了自己的配置。

列出所有有效镜像:

[root@ansible ~]# docker images

Docker容器

Docker容器可以使用命令创建:

[root@ansible ~]# docker run imagename

我们一般不会这样创建容器,因为,一般我们要使用某个镜像来创建一个服务,会给这个容器指定一个容器名,添加端口映射

它会在所有的镜像层之上添加一个可写层。这个可写层有运行在cpu上的进程,而且有两个不同的状态:运行状态(running)和退出状态(exited)。这就是docker容器。当我们使用docker run启动容器,docker容器就进入运行状态,当我们停止容器时,他就进入退出状态。当我们有一个正在运行的docker容器时,从运行态到停止态,我们对他所做的一切变更都会永久的写入到容器的文件系统中。注意:对容器的变更是写入到容器的文件系统,而不是写入到docker镜像中的。我们可以用一个镜像启动多个docker容器,这些容器启动后都是活动的,彼此是互相隔离的。我们对其中一个容器所做的变更只会局限于那个容器本身。如果对容器的底层镜像进行修改,那么当前运行的容器是不受影响的,不会发生自动更新的现象。

64字符的十六进制的字符串来定义容器id,他是容器的唯一标识符。容器之间的交互式依靠容器id识别的,由于容器id的字符太长,我们通常只需键入容器id的前四个字符即可,当然我们还可以使用容器名。

2、容器名称

--name= Assign a name to the container     
为容器分配一个名字,如果没有指定,会自动分配一个随机名称

容器命名方式:

1、使用UUID长命名

("f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778")

2、使用UUID短命名

("f78375b1c487")

3、使用--name自定义容器名

-- name 自定义容器名  注意不能有重复的容器名

注意:

1、这个UUID标识是由Docker deamon生成的。

2、如果你在执行docker run时没有指定--name,那么deamon会自动生成一个随机字符串UUID。

3、但是对于一个容器来说有个name会非常方便,当你需要连接其它容器时或者类似需要区分其它容器时,使用容器名称可以简化操作。无论容器运行在前台或者后台,这个名字都是有效的。

4、如果在使用Docker时有自动化的需求,你可以将containerID输出到指定的文件中(PIDfile)类似于某些应用程序将自身ID输出到文件中,方便后续脚本操作。

--cidfile="": Write the container ID to the file
[root@ansible ~]# docker run -itd --name nginx --hostname nginx -p 998:80 -v /mnt:/usr/share/nginx/html --cidfile=/root/docker_nginx.uuid nginx
9b8a125792a30a963a81232745c4cc54e4fde318618e9b79d3c8a8bfad2f1b42
[root@ansible ~]# cat docker_nginx.uuid 
9b8a125792a30a963a81232745c4cc54e4fde318618e9b79d3c8a8bfad2f1b42

3、镜像名称

镜像是Docker最核心的技术之一,也是应用发布的标准格式。无论你是用docker pull image,或者是在Dockerfile里面写FROM image,下载镜像应该是Docker操作里面最频繁的动作之一了。

下面是在本地机器运行docker images的输出结果:

[root@ansible ~]# docker images
REPOSITORY                  TAG             IMAGE ID       CREATED       SIZE
nginx                       latest          de2543b9436b   8 days ago    142MB
daocloud.io/library/nginx   1.12.0-alpine   09b2eb12555f   4 years ago   15.5

7ef54042dc528fc18180feb58bd9ab34.png

 上图中的ubantu其实不是一个镜像名称,而是代表了一个名为ubantu的Repository,同时在这个Repository下面有一系列打了tag的lmage,lmage的标记是一个GUID,为了方便也可以通过Repository:tag来引用。

那么Registry又是什么呢?Registry存储镜像数据,并且提供拉取和上传镜像的功能。

Registry中镜像是通过Repository来组织的,而每个Repository又包含了若干个Image。

• Registry包含一个或多个Repository

• Repository包含一个或多个Image

• Image用GUID表示,有一个或多个Tag与之关联

注意:

当一个镜像的名称不足以分辨这个镜像所代表的含义时,你可以通过tag将版本信息添加到run命令中,以执行特定版本的镜像。

[root@ansible ~]# docker run ubuntu:14.04

4、命名空间

namespace   空间隔离

cgroup          资源限制

rootfs            文件系统

名字空间是linux内核的一个强大特性。每个容器都有自己单独的名字空间,运行在其中的应用都像是在独立的操作系统中运行一样。名字空间保证了容器之间彼此互不影响。

pid名字空间

不同用户的进程就是通过pid名字空间隔开的,且不同名字空间中可以有相同的pid。

net名字空间

有了pid名字空间,每个名字空间中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过net名字空间实现的,每个net名字空间有独立的网络设备,ip地址,路由表,/proc/net目录。这样每个容器的网络就能够隔离开来。

mnt名字空间

类似chroot,将一个进程放到一个特定的目录执行,mnt名字空间允许不同名字空间的进程看到的文件结构不同,这样每个名字空间中的恶进程所看到的的文件目录就被个离开了。

uts名字空间

每个容器可以有不同的用户的组id,也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。

五、Docker的使用

1、镜像操作

查看centos所有的镜像

[root@ansible ~]# docker search centos

凡是镜像大于100的显示出来,小于100的不显示

[root@ansible ~]#  docker search centos --stars=100
[root@ansible ~]#  docker search centos --filter=stars=100
OFFICIAL [OK]代表官方的
AUTOMATED [OK]代表完整的镜像

拉取镜像:

[root@xingdian ~]# docker pull centos
[root@xingdian ~]# docker pull daocloud.io/library/nginx:1.12.0-alpine
这个地址可以在镜像站上获取

Docker容器技术——真的很细_第17张图片

Docker容器技术——真的很细_第18张图片 查看本地镜像:

[root@ansible ~]# docker image list
[root@ansible ~]# docker images
[root@ansible ~]# docker image ls

[root@ansible ~]# docker images
REPOSITORY                  TAG             IMAGE ID       CREATED       SIZE
nginx                       latest          de2543b9436b   8 days ago    142MB
daocloud.io/library/nginx   1.12.0-alpine   09b2eb12555f   4 years ago   15.5MB

只查看镜像的id

[root@ansible ~]# docker images -q
de2543b9436b
09b2eb12555f

查看镜像详情:

[root@ansible ~]# docker image inspect 镜像名字或者镜像id

 删除镜像:

删除镜像时,镜像不能被容器运行中,需要先停止运行该镜像的容器,然后在删除,删除一个或多个,多个之间用空格隔开,可以使用镜像名称或者id

docker rmi 镜像id加版本号或者镜像名
docker rmi daocloud.io/library/nginx:版本号,不加版本号默认删除latest,没有latest返回错误
docker rmi  09b2eb12555f

删除所有镜像:

[root@ansible ~]# docker rmi $(docker images -q)   
或者
[root@ansible ~]# docker rmi `docker images -q`
只查看所有镜像的id:
[root@ansible ~]# docker images -q 

2、容器操作

查看运行中的容器:

[root@ansible ~]# docker ps 

 查看所有容器:

[root@ansible ~]# docker ps -a

 只查看所有容器的id号

[root@ansible ~]# docker ps -a -q
d8330a8e3c40

 查看容器详细信息

[root@ansible ~]# docker inspect 容器名或者id

使用镜像nginx,启动容器并指定名为server,指定主机名,添加端口映射,目录映射,并放后台运行

先查看一下我们有哪些镜像
[root@ansible ~]# docker images
REPOSITORY                  TAG             IMAGE ID       CREATED       SIZE
nginx                       latest          de2543b9436b   8 days ago    142MB
daocloud.io/library/nginx   1.12.0-alpine   09b2eb12555f   4 years ago   15.5MB

[root@ansible ~]# docker run -itd --name server --hostname nginx -p 999:80 -v /opt:/usr/share/nginx/html nginx
d8330a8e3c40b1b68057318742a9df6ec63553f5a982d98c2f7f2378f10cfdc8
以后台模式启动一个容器,容器命名为server,容器的主机名为nginx,将容器nginx服务的端口映射到宿主机的999端口,将容器nginx服务的默认网站发布目录映射到宿主机的/opt目录。

命令行相关参数介绍:
-i: 以交互模式运行容器,通常与 -t 同时使用;
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-d: 后台运行容器,并返回容器ID;通常与-i -t 同时使用
-p: 端口映射,格式为:主机(宿主)端口:容器端口
--name:为容器指定一个名称;
--hostname:指定容器的hostname;也可以使用-h
-v:文件映射,格式为:主机目录:容器目录

其他参数:
--dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
--dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-e username="ritchie": 设置环境变量;
--cpuset-cpus="0-2" or --cpuset-cpus="0,1,2": 绑定容器到指定CPU运行;
--privileged 以特权模式运行

[root@ansible ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS                                 NAMES
d8330a8e3c40   nginx     "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:999->80/tcp, :::999->80/tcp   server
内容解释:
CONTAINER ID:容器的id号
IMAGE:镜像的名字
COMMAND:启动一个容器时,容器执行的命令
CREATED:创建时间
STATUS:容器状态,up为启动状态,exited为退出状态
PORTS:端口映射
NAMES:容器的名字

 之所以做端口映射是因为容器中的nginx提供的对外服务端口是80,但是我们是无法访问容器的ip及端口号的,所以需要映射到宿主机的999端口(映射的端口不能被占用),这样我们访问宿主机的ip+999端口就能访问到容器nginx的网站发布界面。而做目录映射是为了方便我们修改nginx的网站发布页面的内容。

比如如果不添加目录映射,我们要修改容器nginx服务的网站发布页面,需要进入容器,然后再修改,添加了目录映射之后,我们可以直接在宿主机的映射目录中修改网站发布页面
进入容器的命令:
[root@ansible ~]# docker exec -it server /bin/bash
root@nginx:/#       #可以看到我们进入了容器,exec -it 容器名 /bin/bash 进入容器,注意:有时候/bin/bash无法进入,可以尝试使用/bin/sh或者其他shell。这个nginx就是我们前面设置的容器主机名
root@nginx:/# echo "hello docker">/usr/share/nginx/html/index.html  这样修改比较麻烦

Docker容器技术——真的很细_第19张图片

但是我们可以通过添加目录映射直接在宿主机的映射目录中修改
root@nginx:/# exit   或者ctrl+p+q   #退出容器
[root@ansible ~]# ls /opt/
containerd  index.html
[root@ansible ~]# echo "

hello

" >/opt/index.html

 这样是不是很方便呢

Docker容器技术——真的很细_第20张图片

 启动容器:

docker start  容器名或者id号

关闭容器:

docker stop  容器名或者id号

删除容器:

运行中的容器没法直接删除,需要先关闭在删除,也可以将一个参数-f,强制删除

可以使用容器名或者id号
[root@ansible ~]# docker stop server
[root@ansible ~]# docker rm server
[root@ansible ~]# docker rm -f server

 容器重命名:

docker rename 容器名 新容器名
[root@ansible ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                    PORTS                                 NAMES
9b8a125792a3   nginx     "/docker-entrypoint.…"   16 minutes ago   Up 16 minutes             0.0.0.0:998->80/tcp, :::998->80/tcp   nginx
cebe1aa6c87e   nginx     "/docker-entrypoint.…"   12 hours ago     Exited (0) 12 hours ago                                         server
[root@ansible ~]# docker rename nginx nginx-1
[root@ansible ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                    PORTS                                 NAMES
9b8a125792a3   nginx     "/docker-entrypoint.…"   17 minutes ago   Up 17 minutes             0.0.0.0:998->80/tcp, :::998->80/tcp   nginx-1
cebe1aa6c87e   nginx     "/docker-entrypoint.…"   12 hours ago     Exited (0) 12 hours ago                                         server

容器复制文件到宿主机或者宿主机复制文件到容器

[root@ansible ~]# docker cp /root/server server:/root/   从宿主机拷贝文件到容器
[root@ansible ~]# rm -rf server 
[root@ansible ~]# docker cp server:/root/server /root   从容器拷贝文件到宿主机
[root@ansible ~]# cat server 
123
[root@ansible ~]# docker cp --help 

Usage:  docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
	docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

Copy files/folders between a container and the local filesystem

Use '-' as the source to read a tar archive from stdin
and extract it to a directory destination in a container.
Use '-' as the destination to stream a tar archive of a
container source to stdout.

Options:
  -a, --archive       Archive mode (copy all uid/gid information)
  -L, --follow-link   Always follow symbol link in SRC_PAT

注意:任何不太熟悉的命令都可以通过--help来获取使用手册

六、创建自己的镜像

1、将容器的文件系统打包成tar包

将容器的文件系统打包成tar文件,也就是正在运行的容器直接导出为tar包的镜像文件。

导出:

export
Export a container's filesystem as a tar archive
有两种方式(elated_lovelace为容器名)
第一种:
docker export -o nginx.tar nginx
第二种:
docker export 容器名称 > 镜像.tar

导入:

导入镜像归档文件到其他宿主机:
import
Import the contents from a tarball to create a filesystem image

docker import nginx.tar nginx:v1
docker images   可以看到我们导入的镜像

注意:如果倒入镜像的时候没有起名字随后可以单独起名字(没有名字和tag版本),可以手动添加tag

docker tag 镜像id  版本:版本号

执行之后再用docker images查看镜像时,会发现多了一个镜像id相同,但镜像名字不同的镜像,此时不能使用镜像id删除其中一个镜像,只能用镜像名,否则会把所有镜像id相同的镜像都删除。tag改名的目的不在于单纯改名,而是为了能够把我们的镜像上传到我们的镜像仓库。

2、镜像迁移

保存一台宿主机上的镜像位tar文件,然后可以导入到其他的宿主机上。

save
Save an image(s) to a tar archive
将镜像打包,与下面的load命令相对应
[root@ansible ~]# docker save -o nginx.tar nginx

load
Load an image from a tar archive or STDIN
与上面的save命令相对应,将上面sava命令打包的镜像通过load命令导入
我们可以将打包后的镜像tar文件远程拷贝的其他机器上
[root@ansible ~]# scp nginx.tar 10.0.0.129
...
在10.0.0.129上导入镜像
[root@localhost ~]# docker load < nginx.tar
[root@localhost ~]# docker images   #常看验证
[root@localhost ~]# docker run -itd --name nginx -p 82:81 nginx
能够看到返回64容器id,说明save导出的镜像文件其他机器也可以用

注:

1、tar文件的名称和保存的镜像名称没有关系

2、导入的镜像如果没有名称,自己打tag起名字

扩展:export和save的区别

export:相当于容器快照,容器快照文件将丢弃所有的历史记录和元数据信息

save:没有这个现象,就是完整的

3、通过容器创建本地镜像

背景:

容器运行起来后,又在里面做了一些操作,并且要把操作结果保存到镜像里。

方案:

使用 docker commit 指令,把一个正在运行的容器,直接提交为一个镜像。commit 是提交的意思,类似告诉svn服务器我要生成一个新的版本。

例子:

在容器内部新建了一个文件

[root@ansible ~]# docker run -itd --name nginx-1 -p 83:80 nginx:latest
ef6c8aa7f0bcffad6368740ae172d285d32e08bad2789075fd1d7b9f961e8ab1
[root@ansible ~]# docker exec -it nginx-1 /bin/bash
root@ef6c8aa7f0bc:/# pwd
/
root@ef6c8aa7f0bc:/# touch test.txt
root@ef6c8aa7f0bc:/# exit
exit
[root@ansible ~]# docker commit nginx-1 nginx:v2
sha256:577ea163612a24ff5d54a155b636b83583d678072ce409bfe0051841e3c61b44
[root@ansible ~]# docker images 
REPOSITORY                   TAG             IMAGE ID       CREATED          SIZE
nginx                        v2              577ea163612a   13 seconds ago   142MB
....
[root@ansible ~]# docker save -o nginx.tar nginx:v2
[root@ansible ~]# ls
nginx.tar
[root@ansible ~]# scp nginx.tar 10.0.0.129

在10.0.0.129上验证:
[root@localhost ~]# ls
anaconda-ks.cfg  nginx.tar 
[root@localhost ~]# docker load < nginx.tar 
fd95118eade9: Loading layer [==================================================>]   83.9MB/83.9MB
d253f69cb991: Loading layer [==================================================>]     62MB/62MB
dfe7577521f0: Loading layer [==================================================>]  3.072kB/3.072kB
18be1897f940: Loading layer [==================================================>]  4.096kB/4.096kB
09be960dcde4: Loading layer [==================================================>]  3.584kB/3.584kB
a059c9abe376: Loading layer [==================================================>]  7.168kB/7.168kB
Loaded image: nginx:latest
[root@localhost ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
nginx        latest    de2543b9436b   9 days ago   142MB
[root@localhost ~]# docker run -itd --name nginx -p 83:80 nginx:latest
7bdd153876843dabdbfab4ad61f0da71fac64b48b85040bfa6d2228f651d118d
[root@localhost ~]# docker exec -it nginx /bin/bash
可以看到能使用这个拷贝过来的镜像
# docker commit -m "my images version1" -a "xingdian" 108a85b1ed99 daocloud.io/ubuntu:v2
sha256:ffa8a185ee526a9b0d8772740231448a25855031f25c61c1b63077220469b057
    -m                        添加注释
    -a                        作者
    108a85b1ed99              容器环境id
    daocloud.io/ubuntu:v2     镜像名称:hub的名称/镜像名称:tag 
    -p,–pause=true           提交时暂停容器运行

七、通过dockerfile创建镜像

Docker 提供了一种更便捷的方式,叫做Dockerfile

Dockerfile build命令用语根据给定的Dockerfile构建Docker镜像。

1、docker build语法:

[root@localhost ~]# docker build --help

Usage:  docker build [OPTIONS] PATH | URL | -

Build an image from a Dockerfile

常用选项说明

选项 含义
--build-arg 设置构建时的变量
--no-cache 默认false。设置该选项,将不使用Build Cache构建镜像
--pull 默认false。设置该选项,总是尝试pull镜像的最新版本
--compress 默认false。设置该选项,将使用gzip压缩构建的上下文
--disable-content-trust 默认true。设置该选项,将对镜像进行验证
--file, -f Dockerfile的完整路径,默认值为‘PATH/Dockerfile’
--isolation 默认--isolation="default",即Linux命名空间;其他还有process或hyperv
--label 为生成的镜像设置metadata
--squash 默认false。设置该选项,将新构建出的多个层压缩为一个新层,但是将无法在多个镜像之间共享新层;设置该选项,实际上是创建了新image,同时保留原有image。
-tag, -t 镜像的名字及tag,通常name:tag或者name格式;可以在一次构建中为一个镜像设置多个tag
--network 默认default。设置该选项,Set the networking mode for the RUN instructions during build
--quiet, -q 默认false。设置该选项,Suppress the build output and print image ID on success
--force-rm 默认false。设置该选项,总是删除掉中间环节的容器
--rm 默认--rm=true,即整个构建过程成功后删除中间环节的容器

示例:

docker build -t daocloud.io/nginx:v1 .
docker build  是docker创建镜像的命令 
-t 是标识新建的镜像属于 soso的 bbauto镜像 
:v1 是tag 
"."是用来指明我们的使用的Dockerfile文件当前目录的 

 Dockerfile中常用的命令

1、FROM 指定基础镜像
2、RUN  运行命令
3、ENV  设定环境变量
4、ADD  添加文件到容器: 压缩包   自动帮你解压
5、COPY  文件拷贝
6、WORKDIR  指定工作目录
7、EXPOSE  暴露端口
8、CMD  指定要运行的命令
9、MAINTAINER  指定作者  邮件等描述
添加文件到镜像的时候可以用ADD也可以用COPY,如果文件是tar包可用ADD会自动解压,使用RUN命令时将将命令清单写到一行,可以减少镜像的大小

案例:通过Dockerfile构建nginx镜像

这之前我们可以拉取一个centos7的镜像
[root@ansible ~]# docker run -itd --privileged --name  zcg daocloud.io/centos:7 /sbin/init
--privileged  以特权身份进入容器,一般会和/sbin/bash  用这个命令进入容器时,我们下载服务之后可以启动它,而不用特权身份进入,下载完服务启东市会提示没有权限。
[root@ansible ~]# mkdir nginx
[root@ansible ~]# cd nginx
[root@ansible nginx]# wget http://nginx.org/download/nginx-1.22.0.tar.gz
vim Dockerfile
FROM daocloud.io/library/centos:7
RUN rm -rf /etc/yum.repos.d/*
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://repo.huaweicloud.com/repository/conf/CentOS-7-reg.repo
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum clean all && yum makecache fast
RUN yum -y install gcc openssl openssl-devel pcre-devel zlib-devel make
ADD nginx-1.22.0.tar.gz /usr/local
WORKDIR /usr/local/nginx-1.22.0
RUN ./configure --prefix=/usr/local/nginx
RUN make && make install
WORKDIR /usr/local/nginx
RUN rm -rf /usr/local/nginx-1.22.0
ENV NGINX_HOME=/usr/local/nginx
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/nginx/sbin
EXPOSE 80
CMD ["nginx","-g","daemon off;"]
[root@ansible nginx]# docker build -t zcg-nginx:v1 .
....   等看到success就说明构建镜像成功了
[root@ansible nginx]# docker run -itd --name zcg-nginx -p 85:80 -v /opt:/usr/share/nginx/html zcg-nginx:v1 
然后浏览器访问测试

Docker容器技术——真的很细_第21张图片

2、PATH|URL|- 说明

给出命令执行的上下文。

上下文可以是构建执行所在的本地路径,也可以是远程URL,如Git库、tarball或文本文件等。如果是Git库,如https://github.com/docker/rootfs.git#container:docker,则隐含先执行git clone --depth 1 --recursive,到本地临时目录;然后再将该临时目录发送给构建进程。

构建镜像的进程中,可以通过ADD命令将上下文中的任何文件(注意文件必须在上下文中)加入到镜像中。

-表示通过STDIN给出Dockerfile或上下文。

示例:

docker build - < Dockerfile

 说明:该构建过程只有Dockerfile,没有上下文

docker build - < context.tar.gz

说明:其中Dockerfile位于context.tar.gz的根路径

docker build -t champagne/bbauto:latest -t champagne/bbauto:v2.1 .
docker build -f dockerfiles/Dockerfile.debug -t myapp_debug .

 创建镜像所在的文件夹和Dockerfile文件,并在Dockerfile中写入指令,每条指令都会更新镜像的信息

mkdir nginx
cd nginx
touch Dockerfile
vim Docker
FROM daocloud.io/library/centos:7
RUN rm -rf /etc/yum.repos.d/*
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://repo.huaweicloud.com/repository/conf/CentOS-7-reg.repo
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum clean all && yum makecache fast
RUN yum -y install gcc openssl openssl-devel pcre-devel zlib-devel make
ADD nginx-1.22.0.tar.gz /usr/local
WORKDIR /usr/local/nginx-1.22.0
RUN ./configure --prefix=/usr/local/nginx
RUN make && make install
WORKDIR /usr/local/nginx
RUN rm -rf /usr/local/nginx-1.22.0
ENV NGINX_HOME=/usr/local/nginx
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/nginx/sbin
EXPOSE 80
CMD ["nginx","-g","daemon off;"]

 格式说明:

每行命令都是以INSTRUCTION statement 形式,就是命令+清单的模式,命令要大写,"#"是注解。
FROM命令是告诉docker我们的基础镜像是什么
MAINTAINER是描述镜像的创建人
RUN命令是镜像内部执行。就是说他后面的命令应该是针对镜像可以运行的命令。

1、FROM 指定基础镜像
2、RUN  运行命令
3、ENV  设定环境变量
4、ADD  添加文件到容器: 压缩包   自动帮你解压
5、COPY  文件拷贝
6、WORKDIR  指定工作目录
7、EXPOSE  暴露端口
8、CMD  指定要运行的命令
9、MAINTAINER  指定作者  邮件等描述

案例:使用Docker部署微服务项目

实验准备:

需要四个项目分jar包,一个前端项目的包,一个数据库,两个数据库数据文件,jar包,前端项目包以及数据库文件,都是从别人那找到的,我们只需要利用这几个资源部署我们的项目

实验环境:

一台虚拟机(两核,4G),安装docker

实验过程

1、为这四个项目的jar包创建四个目录。并把对应的jar包和jdk包拷贝进去,并创建对应的Dockerfile文件
[root@ansible ~]# mkdir 1
[root@ansible ~]# mkdir 2
[root@ansible ~]# mkdir 3
[root@ansible ~]# mkdir 4
[root@ansible ~]# cd 1/
[root@ansible 1]# ls
Dockerfile  jdk-8u211-linux-x64.tar.gz  tensquare_eureka_server-1.0-SNAPSHOT.jar
[root@ansible 1]# cat Dockerfile 
FROM daocloud.io/library/centos:7
ADD jdk-8u211-linux-x64.tar.gz /usr/local
RUN mv /usr/local/jdk1.8.0_211 /usr/local/java
ENV JAVA_HOME /usr/local/java/
ENV PATH $PATH:$JAVA_HOME/bin
COPY tensquare_eureka_server-1.0-SNAPSHOT.jar /usr/local
EXPOSE 10086
CMD java -jar /usr/local/tensquare_eureka_server-1.0-SNAPSHOT.jar
[root@ansible ~]# cd 2
[root@ansible 2]# ls
Dockerfile  jdk-8u211-linux-x64.tar.gz  tensquare_zuul-1.0-SNAPSHOT.jar
[root@ansible 2]# cat Dockerfile 
FROM daocloud.io/library/centos:7
ADD jdk-8u211-linux-x64.tar.gz /usr/local
RUN mv /usr/local/jdk1.8.0_211 /usr/local/java
ENV JAVA_HOME /usr/local/java/
ENV PATH $PATH:$JAVA_HOME/bin
COPY tensquare_zuul-1.0-SNAPSHOT.jar /usr/local
EXPOSE 10086
CMD java -jar /usr/local/tensquare_zuul-1.0-SNAPSHOT.jar
[root@ansible ~]# cd 3
[root@ansible 3]# ls
Dockerfile  jdk-8u211-linux-x64.tar.gz  tensquare_admin_service-1.0-SNAPSHOT.jar
[root@ansible 3]# cat Dockerfile 
FROM daocloud.io/library/centos:7
ADD jdk-8u211-linux-x64.tar.gz /usr/local
RUN mv /usr/local/jdk1.8.0_211 /usr/local/java
ENV JAVA_HOME /usr/local/java/
ENV PATH $PATH:$JAVA_HOME/bin
COPY tensquare_admin_service-1.0-SNAPSHOT.jar /usr/local
EXPOSE 10086
CMD java -jar /usr/local/tensquare_admin_service-1.0-SNAPSHOT.jar
[root@ansible ~]# cd 4
[root@ansible 4]# ls
Dockerfile  jdk-8u211-linux-x64.tar.gz  tensquare_gathering-1.0-SNAPSHOT.jar
[root@ansible 4]# cat Dockerfile 
FROM daocloud.io/library/centos:7
ADD jdk-8u211-linux-x64.tar.gz /usr/local
RUN mv /usr/local/jdk1.8.0_211 /usr/local/java
ENV JAVA_HOME /usr/local/java/
ENV PATH $PATH:$JAVA_HOME/bin
COPY tensquare_gathering-1.0-SNAPSHOT.jar /usr/local
EXPOSE 10086
CMD java -jar /usr/local/tensquare_gathering-1.0-SNAPSHOT.jar
2、利用这四个Dockerfile文件构建镜像
[root@ansible ~]# cd 1
[root@ansible 1]# docker build -t zcg-eureka .
....succes
[root@ansible ~]# cd 2
[root@ansible 2]# docker build -t zcg-zuul .
...success
[root@ansible ~]# cd 3
[root@ansible 3]# docker build -t zcg-admin .
...success
[root@ansible ~]# cd 4
[root@ansible 4]# docker build -t zcg-gathering .
...success
3、拉取数据库mysql镜像
[root@ansible ~]# docker pull daocloud.io/library/mysql:5.7.7
....
[root@ansible ~]# docker run -itd --name mysql -p 30023:3306 -e MYSQL_ROOT_PASSWORD=mysql cf8a22028fe7
数据要导入数据库就需要登录用户和密码,用户是默认root,密码则需要一个docker的参数-e,将密码传到数据库,MYSQL_ROOT_PASSWORD这个变量是固定的,后边的密码需要跟jar中的密码对应
4、数据导入
容器中的数据库运行起来了,但是我们需要往里边导入数据,所以需要下载一个数据库的客户端,就使用mariadb,比较快
[root@ansible ~]# yum -y install mariadb
[root@ansible ~]# mysql -uroot -pmysql -h 10.0.0.220 -P30023
MySQL [(none)]> create database tensquare_gathering charset=utf8;
MySQL [(none)]> create database tensquare_user charset=utf8;
MySQL [(none)]> use tensquare_user;
MySQL [(none)]> source /root/tensquare_user.sql;
MySQL [(none)]> use tensquare_gathering;
MySQL [(none)]> source /root/tensquare_gathering.sql;

做完上面的步骤接下来需要一次使用构建的四个镜像运行容器,一次运行eureka、zuul、 gathering、 admin ,对应的端口映射如下:

Docker容器技术——真的很细_第22张图片

[root@ansible ~]# docker run -itd --name eureka -p 30020:10086 zcg-eureka
[root@ansible ~]# docker run -itd --name zuul -p 30021:10020 4ff1ba324b3e
[root@ansible ~]# docker run -itd --name gathering -p 30022:9002 9478d97e43b7
[root@ansible ~]# docker run -itd --name admin -p 30024:9001 3762f7506eb5

项目和数据库都部署好了,我们还需要一个前端项目连接后端数据库

利用上面那个实验构建的nginx镜像,或者自己构建的nginx镜像,来部署前端项目
对应的前端项目包我们把它放到/opt/目录下,等会做目录映射
[root@ansible ~]# ls /opt/
dist
[root@ansible ~]# chmod 777 /opt/dist -R  #把dist目录中的文件权限全部设置为777,不然最后访问项目的时候会出现403
然后使用nginx镜像运行容器
[root@ansible ~]# docker run -itd --name nginx -p 81:80 -v /opt/dist/:/usr/local/nginx/html 5b2e2d183450

查看一下运行中的容器

[root@ansible ~]# docker ps 
CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS        PORTS                                                      NAMES
e29d488ee8fb   3762f7506eb5   "/bin/sh -c 'java -j…"   16 hours ago   Up 16 hours   10086/tcp, 0.0.0.0:30024->9001/tcp, :::30024->9001/tcp     admin
2127fe6f995a   9478d97e43b7   "/bin/sh -c 'java -j…"   16 hours ago   Up 16 hours   10086/tcp, 0.0.0.0:30022->9002/tcp, :::30022->9002/tcp     gathering
bac9b2c04159   4ff1ba324b3e   "/bin/sh -c 'java -j…"   16 hours ago   Up 16 hours   10086/tcp, 0.0.0.0:30021->10020/tcp, :::30021->10020/tcp   zuul
6d335c65b37d   5b2e2d183450   "nginx -g 'daemon of…"   16 hours ago   Up 16 hours   0.0.0.0:81->80/tcp, :::81->80/tcp                          nginx
ac10d73e8c06   cf8a22028fe7   "/entrypoint.sh mysq…"   16 hours ago   Up 16 hours   0.0.0.0:30023->3306/tcp, :::30023->3306/tcp                mysql
9d68ffdb7f3a   zcg-eureka     "/bin/sh -c 'java -j…"   17 hours ago   Up 17 hours   0.0.0.0:30020->10086/tcp, :::30020->10086/tcp              eureka

只有这六个容器都运行起来,并且可以看到对应的端口映射,我们才能访问到项目

Docker容器技术——真的很细_第23张图片

 进入之后可以看到我们导入的数据,其实也没啥

Docker容器技术——真的很细_第24张图片

八、Docker-compose

1、docke-compose介绍

Docker-compose是一个用来定义和运行复杂应用的Docker工具。一个使用Docker容器的应用,通常由多个容器组成。使用Docker-compose不再需要使用shell脚本来启动容器。

compose通过一个配置文件来管理多个docker容器,在配置文件中,所有的容器通过services来定义,然后使用docker-compose脚本来启动,停止和重启应用,和应用中的服务以及所有依赖的容器,非常适合组合使用多个容器进行开发的场景。

官方教程:​​​​​​https://docs.docker.com/compose/

2、Docker安装

wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
mv docker-ce.repo /etc/yum.repos.d/
yum -y install docker-ce
systemctl start docker-ce && systemctl enable docker
docker -v

配置国内镜像源

vim /etc/docker/daemon.json
{ "registry-mirrors": ["https://cq20bk8v.mirror.aliyuncs.com"] }

3、docker-compose安装

pip3安装

[root@docker-compose ~]# yum install epel-release
[root@docker-compose ~]# yum install python3-pip 
[root@docker-compose ~]# pip3 install --upgrade pip 
[root@docker-compose ~]# pip3 install docker-compose 

这里会报错:ModuleNotFoundError: No module named 'setuptools_rust'
解决方法:pip3 install -U pip setuptools
 
 
[root@docker-compose ~]# docker-compose --version

二进制安装

从github上下载docker-compose二进制文件安装

[root@docker-compose ~]# curl -L https://get.daocloud.io/docker/compose/releases/download/v2.5.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
[root@docker-compose ~]# chmod +x /usr/local/bin/docker-compose
[root@docker-compose ~]# docker-compose -v
[root@ansible docker]# docker-compose -v
Docker Compose version v2.5.0
你可以通过修改URL中的版本,自定义需要的版本

4、docker-compose文件结构和示例

docker-compose文件结构

docker-compose.yml:

version: "3"
services:
 
  redis:
    image: redis:alpine
    ports:
      - "6379"
    networks:
      - frontend
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure
 
  db:
    image: postgres:9.4
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - backend
    deploy:
      placement:
        constraints: [node.role == manager]
 
  vote:
    image: dockersamples/examplevotingapp_vote:before
    ports:
      - 5000:80
    networks:
      - frontend
    depends_on:
      - redis
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
      restart_policy:
        condition: on-failure
 
  result:
    image: dockersamples/examplevotingapp_result:before
    ports:
      - 5001:80
    networks:
      - backend
    depends_on:
      - db
    deploy:
      replicas: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure
 
  worker:
    image: dockersamples/examplevotingapp_worker
    networks:
      - frontend
      - backend
    deploy:
      mode: replicated
      replicas: 1
      labels: [APP=VOTING]
      restart_policy:
        condition: on-failure
        delay: 10s
        max_attempts: 3
        window: 120s
      placement:
        constraints: [node.role == manager]
 
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    stop_grace_period: 1m30s
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
 
networks:
  frontend:
  backend:
 
volumes:
  db-data:

docker-compose使用示例

通过docker-compose构建一个在docker中运行的基于python flask框架的web应用

注意:确保安装了Docker Engine和Docker Compose。不需要能装python或redis,因为这两个都是有Docker镜像提供的。

1、定义python应用

1.创建工程目录

[root@docker-compose ~]# mkdir compose_test
[root@docker-compose ~]# cd compose_test
[root@docker-compose compose_test]# mkdir src  #源码文件夹
[root@docker-compose compose_test]# mkdir docker #docker配置文件夹  

目录结构:

└── compose_test
    ├── docker
    │   └── docker-compose.yml
    ├── Dockerfile
    └── src
        ├── app.py
        └── requirements.txt

2.在compose_test/src/目录下创建python flask应用compose_test/src/app.py

[root@docker-compose ~]# cat compose_test/src/app.py
from flask import Flask
from redis import Redis
 
app = Flask(__name__)
redis = Redis(host='redis', port=6379)
 
@app.route('/')
def hello():
    count = redis.incr('hits')
    return 'Hello World! I have been seen {} times.\n'.format(count)
 
if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

3.创建python需求稳健compose_test/src/requirements.txt

[root@docker-compose ~]# cat compose_test/src/requirements.txt
flask
redis

2、创建容器的Dockerfile文件

一个容器一个Dockerfile文件,在compose_test/目录中创建Dockerfile文件:

[root@docker-compose ~]# cat compose_test/Dockerfile
FROM python:3.7
 
COPY src/ /opt/src
WORKDIR /opt/src
 
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

注释:Docker文件告诉docker了一下信息:

从python3.7的镜像开始构建一个容器镜像

复制src(即compose_test/src)目录到容器中的/opt/src目录。

将容器的工作目录设置为/opt/src(通过docker exec -it 容器id /bin/bash 进入容器后的默认目录)

安装python依赖关系

将容器的默认命令设置为python app.py

3、定义docker-compose脚本

在compose_test/docker/目录下创建docker-compose.yml文件,并在里面定义服务,内容如下:

version: '3'
services:
  web:    #自定义的容器名
    build: ../     #使用当前docker-compose.yml文件所在目录的上级目录(compose_test/Dockerfile)中的Dockerfile构建映像。 
    ports:  
     - "5000:5000"    #端口映射
  redis:
    image: redis:3.0.7   redis服务使用从docker hub提取官方redis镜像3.07版本

4、使用compose构建并运行你的应用程序

在compose_test/docker/目录下执行docker-compose.yml文件:

docker-compose up
# 若是要后台运行: $ docker-compose up -d
# 若不使用默认的docker-compose.yml 文件名:
docker-compose -f server.yml up -d 

浏览器访问测试:

Docker容器技术——真的很细_第25张图片

5、编辑compose文件以添加文件绑定挂载

上面的代码是在构建时静态复制到容器中的,即通过Dockerfile文件中的COPY src /opt/src命令实现物理主机中的源码复制到容器中,这样在后续物理主机src目录中代码的更改不会反应到容器中。

可以通过volumes关键字实现物理主机目录挂载到容器中的功能(同时删除Dockerfile中的COPY指令,不需要创建镜像时将代码打包进镜像,而是通过volums动态挂载,容器和物理host共享数据卷):

version: '3'
services:
  web:
    build: ../
    ports:
     - "5000:5000"
    volumes:
     - ../src:/opt/src
  redis:
    image: "redis:3.0.7"

 通过volumes(卷)将主机上的项目目录(compose_test/src)挂载到容器中的/opt/src目录,允许实时修改代码,而无需重新构建镜像

6、compose常用服务配置参考

compose文件是一个定义服务,网络个卷的YAML文件。compose文件的默认文件名为docker-compose.yml。

与docker运行一样,默认情况下,Dockerfile中的指定选项(例如:CMD、EXPOSE、VOLUME、ENV)都被遵守,你不需要在docker-compose.yml中在此指定他们。

同时你可以使用类似Bash的${VARIABLE}语法在配置值中使用环境变量,有关详细信息,请参阅变量替换。

build

[root@docker-compose ~]# mkdir test
[root@docker-compose ~]# mkdir test/docker
[root@docker-compose test]# tree docker/
docker/
├── dir
│   ├── Dockerfile
│   └── index.html
├── docker-compose.yaml

[root@docker-compose test]# cat docker/dir/Dockerfile 
FROM daocloud.io/library/centos:7
WORKDIR /usr/local/src/
ENV NG_VERSION nginx-1.21.0
RUN yum -y install epel-release &&  yum -y install wget && wget http://nginx.org/download/$NG_VERSION.tar.gz && tar xzvf $NG_VERSION.tar.gz && yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel && yum install -y pcre-devel libxslt-devel gd-devel GeoIP GeoIP-devel GeoIP-data
RUN yum clean all
RUN useradd -M -s /sbin/nologin nginx
WORKDIR /usr/local/src/$NG_VERSION
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
ADD ./index.html /usr/local/nginx/html
VOLUME /usr/local/nginx/html
ENV PATH /usr/local/nginx/sbin:$PATH
EXPOSE 80/tcp
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]

[root@docker-compose test]# cat docker/dir/index.html 
hello word

[root@docker-compose test]# cat docker/docker-compose.yaml 
version: '2'
services:
  nginx-2:
    ports:
      - "83:80"
    build: ./dir
[root@docker-compose test]# cd docker
[root@docker-compose docker]# docker-compose up -d

浏览器访问

Docker容器技术——真的很细_第26张图片

 build可以指定包含构建上下文的路径:

Docker容器技术——真的很细_第27张图片

也可以作为一个对象,该对象具有上下文路径和指定的Dockerfile文件:Docker容器技术——真的很细_第28张图片

nginx-2服务将会通过./dir目录下的Dockerfile-abc文件构建容器镜像

如果同时指定image和build,则compose会通过指定的目录构建容器镜像,二构建的镜像名为image中指定的镜像名和标签

[root@docker docker]# cat docker-compose.yaml 
version: '2'
services:
  nginx-2:
    image: nginx:v2
    build: ./dir
    [root@docker docker]# docker-compose up -d

 这将由./dir构建的名为nginx-2和标记为tag的镜像。可以认为是指定镜像名称;

你可能感兴趣的:(docker,容器,运维)