聊聊Docker

Docker是基于Go语言开发的开源项目

官网
在这里插入图片描述
文档地址 Docker文档是超级详细的,就是看不懂而已

仓库地址

Docker能干啥

  • 以前的虚拟技术

    虚拟机技术的缺点

    1、资源占用十分多

    2、冗余步骤多

    3、启动很慢
    在这里插入图片描述

  • 容器化技术
    在这里插入图片描述
    ​ 比较Docker和虚拟机技术的不同

​ 1、传统虚拟机虚拟出一套硬件,运行一个完整的操作系统,然后再这个系统上安装和运行软件

​ 2、容器内的应用直接运行在宿主机的内容,容器没有自己的内核,也没有虚拟我们的硬件,所以就轻便了

​ 3、每个容器间是互相隔离的,每个容器内都有一个属于自己的文件系统,互不影响

  • DevOps(开发运维)

    • 应用更快速的交付和部署

      传统:一堆帮助文档,安装程序

      Docker:打包镜像发布测试,一键运行

    • 更快捷的升级和扩缩容

      使用了Docker之后,我们部署的应用就和搭积木一样

Docker的基本组成

Docker的基本组成
在这里插入图片描述
镜像(image):

docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像——>run——>tomcat01容器(提供服务器),通过这个镜像可以创建多个容器。

容器(container):

Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建

启动,停止,删除,基础命令

目前就可以把这个容器理解为一个简易的Linux系统

仓库(reponsitory):

仓库就是存放镜像的地方

仓库分为公有仓库和私有仓库

Docker Hub

阿里云…都有容器服务器(配置镜像加速)

Docker安装

环境准备

1、CentOS8

2、Xshell

环境查看

#系统内核是3.10以上
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# uname -r
4.18.0-147.5.1.el8_1.x86_64

安装

#1、卸载旧版本
yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine
    
#2、下载需要的安装包
sudo yum install -y yum-utils

#3、设置镜像的仓库
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo#默认是国外的
yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo#推荐使用阿里云的,十分的快
    
#4、更新yum软件包的索引
yum makecache

#5安装新版的containerd.io
dnf install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm
	
#6、安装docker相关的内容 docker-ce 社区版 ee企业版
sudo yum install docker-ce docker-ce-cli

#7、启动Docker
systemctl start docker

#8、判断是否启动成功
docker version

在这里插入图片描述

#8、执行HelloWord程序
docker run hello-word

在这里插入图片描述
在这里插入图片描述

#9、查看下载的hello-world镜像
docker images

在这里插入图片描述

#10、卸载Docker
#卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
#删除目录资源
rm -rf /var/lib/docker

阿里云镜像加速

在这里插入图片描述
找到镜像加速器
在这里插入图片描述
配置使用

sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://ks6vp0jf.mirror.aliyuncs.com"]
}
EOF

sudo systemctl daemon-reload

sudo systemctl restart docker
#列出防火墙开放的端口
firewall-cmd --zone=public --list-ports
#打开8080端口
firewall-cmd --zone=public --add-port=8080/tcp --permanent
#项目部署
docker run -it -v /home/HaveFunResources/pictures:/home/HaveFunResources/pictures --net=host --name demo -p 8080:8080 demo

底层原理

Docker是怎么工作的?

Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问

DockerServer接收到Docker-Client的指令,就会执行这个命令
在这里插入图片描述

Docker为什么比VM快?

1、Docker有着比虚拟机更少的抽象层

2、Docker利用的是宿主机的内核,vm需要是Guest OS
在这里插入图片描述
所以说,新建一个容器的时候,docker不需要像虚拟机一样重新加载一个操作系统内核,避免引导性的操作,虚拟机是加载Guest OS,分钟级别

Docker是利用宿主机的操作系统,省略掉这个复杂的过程,秒级。

Docker的常用命令

帮助命令

docker version				#显示docker的版本信息
docker info					#显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help		   #帮助命令

帮助文档地址:https://docs.docker.com/reference/

镜像命令

docker images 查看所有本地的主机上的镜像

[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

#解释
REPOSITORY				镜像的仓库源
TAG 					镜像的标签
IMAGE ID				镜像的id
CREATED 				镜像创建的时间
SIZE					镜像的大小

#可选项
  -a, --all             #列出所有镜像
  -q, --quiet           #只显示镜像的ID

docker search搜索镜像

[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker search mysql
NAME                              DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
mysql                             MySQL is a widely used, open-source relation…   10103               [OK]                
mariadb                           MariaDB is a community-developed fork of MyS…   3708                [OK]                
mysql/mysql-server                Optimized MySQL Server Docker images. Create…   738                                     [OK]
#可选项 通过STARS来过滤
docker search mysql --filter=STARS=3000 #会去搜索镜像STARS大于3000的

docker pull 下载镜像

#下载镜像 docker pull 镜像名[:tag]
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker pull mysql
Using default tag: latest  #如果不写tag,默认最新
latest: Pulling from library/mysql
bb79b6b2107f: Pull complete #分层下载 docker images的核心 联合文件系统
49e22f6fb9f7: Pull complete 
842b1255668c: Pull complete 
9f48d1f43000: Pull complete 
c693f0615bce: Pull complete 
8a621b9dbed2: Pull complete 
0807d32aef13: Pull complete 
a56aca0feb17: Pull complete 
de9d45fd0f07: Pull complete 
1d68a49161cc: Pull complete 
d16d318b774e: Pull complete 
49e112c55976: Pull complete 
Digest: sha256:8c17271df53ee3b843d6e16d46cff13f22c9c04d6982eb15a9a47bd5c9ac7e2d #签名,防伪
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest #真实地址

#即:docker pull mysql 等价于 docker pull docker.io/library/mysql:latest


#指定版本下载:
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
bb79b6b2107f: Already exists 
49e22f6fb9f7: Already exists 
842b1255668c: Already exists 
9f48d1f43000: Already exists 
c693f0615bce: Already exists 
8a621b9dbed2: Already exists 
0807d32aef13: Already exists 
f15d42f48bd9: Pull complete 
098ceecc0c8d: Pull complete 
b6fead9737bc: Pull complete 
351d223d3d76: Pull complete 
Digest: sha256:4d2b34e99c14edb99cdd95ddad4d9aa7ea3f2c4405ff0c3509a29dc40bcb10ef
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

docker rmi 删除镜像

[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker rmi -f 镜像id   #删除指定的镜像
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker rmi -f 镜像id 镜像id 镜像id #删除多个镜像
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker rmi -f $(docker images -qa)  #删除全部镜像

容器命令

说明:有了镜像才可以创建容器,linux,下载一个centos来测试学习

docker pull centos

新建容器并启动

docker run [可选参数] image
#参数说明
--name="name" #容器名字 用来区分容器
-d            #后台方式运行
-it			  #使用交互方式运行,进入容器查看内容
-p			  #小写
	-p ip:主机端口:容器端口
	-p 主机端口:容器端口(常用)
	-p	容器端口
	容器端口
-P			  #随机指定端口(大写)

#测试,启动并进入容器,主机名就是镜像id
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker run -it centos /bin/bash
[root@258ac6601c93 /]# ls  #查看容器内的centos,但是是基础版本,很多命令不完善
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@258ac6601c93 /]# exit #退出容器
exit

列出所有运行的容器

#docker ps 命令
	    #列出当前运行中的容器
	-a  #列出当前运行中的容器,带出历史运行过的容器
	-n=?#列出最近创建的容器
	-q  #只显示容器的编号
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                          PORTS               NAMES
258ac6601c93        centos              "/bin/bash"         4 minutes ago       Exited (0) About a minute ago                       compassionate_driscoll
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps -n=1
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
258ac6601c93        centos              "/bin/bash"         7 minutes ago       Exited (0) 5 minutes ago                       compassionate_driscoll

退出容器

exit            #直接容器停止不退出

Ctrl + p + Q    #容器不停止退出
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker run -it centos
[root@02a809f869be /]# [root@iZ2ze5wj5w33v3gyd9kv1bZ /]# cd ..
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
02a809f869be        centos              "/bin/bash"         51 seconds ago      Up 50 seconds                           amazing_poitras

删除容器

docker rm 容器id                          #删除指定的容器,不能删除正在运行的容器,如果要强行删除,加-f
docker rm -f $(docker ps -aq)            #删除全部容器
docker ps -a -q | xargs docker rm        #删除全部容器

启动和停止容器的操作

docker start 容器id   #启动
docker restart 容器id	#重启
docker stop 容器id	#停止
docker kill 容器id    #杀死,如果停止报错,直接强行干掉

[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
02a809f869be        centos              "/bin/bash"         7 minutes ago       Up 7 minutes                            amazing_poitras
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker stop 02a809f869be
02a809f869be
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
02a809f869be        centos              "/bin/bash"         7 minutes ago       Exited (0) 9 seconds ago                        amazing_poitras
258ac6601c93        centos              "/bin/bash"         17 minutes ago      Exited (0) 15 minutes ago                       compassionate_driscoll
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker start 02a809f869be
02a809f869be
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
02a809f869be        centos              "/bin/bash"         8 minutes ago       Up 6 seconds                            amazing_poitras

常用的其他命令

后台启动容器

#命令 docker run -d 镜像名
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker run -d centos

#问题docker ps,发现centos停止了

#常见的坑,docker 容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止
#nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了。

查看日志

docker logs -tf --tail 10 容器  #没有日志

#自己编写一段shell脚本
docker run -d centos /bin/sh -c "while true;do echo phz;sleep 1;done"
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a20ddc3959fd        centos              "/bin/bash"         6 minutes ago       Up 6 minutes                            naughty_heyrovsky
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker run -d centos /bin/sh -c "while true;do echo phz;sleep 1;done"
be6dd3b0adcdf7fe7a69da47d113e835bec20711469a01ad613ea5403bf02e42
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
be6dd3b0adcd        centos              "/bin/sh -c 'while t…"   4 seconds ago       Up 3 seconds                            youthful_boyd
a20ddc3959fd        centos              "/bin/bash"              7 minutes ago       Up 6 minutes                            naughty_heyrovsky

#显示日志
	-tf			#显示日志
	--tail number #要显示的日志条数
docker logs -tf --tail 10 be6dd3b0adcd

在这里插入图片描述
查看容器中的进程命令

[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker ps
CONTAINER ID    IMAGE               COMMAND        CREATED             STATUS              PORTS               NAMES
65002f0bcb84    centos              "/bin/sh"      56 seconds ago      Up 54 seconds                           sad_wescoff
[root@iZ2ze5wj5w33v3gyd9kv1bZ /]# docker top 65002f0bcb84
UID           PID                 PPID          C            STIME         TTY                 TIME                CMD
root          31347               31331         0            10:29         pts/0               00:00:00            /bin/sh

查看镜像的元数据

#命令
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker inspect 65002f0bcb84

进入当前正在运行的容器

#我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置

#方式一
#命令
docker exec -it 容器id bashShell

[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker ps
CONTAINER ID    IMAGE       COMMAND         CREATED              STATUS              PORTS               NAMES
6e8f7795e92a    centos      "/bin/bash"     About a minute ago   Up About a minute                       agitated_driscoll
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker ps -a
CONTAINER ID      IMAGE           COMMAND         CREATED          STATUS              PORTS               NAMES
6e8f7795e92a      centos          "/bin/bash"     2 minutes ago    Up About a minute                       agitated_driscoll
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker exec -it 6e8f7795e92a /bin/bash
[root@6e8f7795e92a /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@6e8f7795e92a /]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 04:34 pts/0    00:00:00 /bin/bash
root        20     0  0 04:36 pts/1    00:00:00 /bin/bash
root        35    20  0 04:38 pts/1    00:00:00 ps -ef

#方式二
docker attach 容器id

#测试
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker attach 6e8f7795e92a
#正在执行的代码。。。。。


#区别:
#docker exec               #进入容器后开启一个新的终端,可以在里面操作(常用)
#docker attach             #进入容器正在执行的终端,不会启动新的进程。

从容器内拷贝文件到主机上

docker cp 容器id:容器内路径   目的主机路径
  • 先创建一个centos容器,并在其home文件夹下新建一个文件
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker attach 5b402a1c7c33
[root@5b402a1c7c33 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@5b402a1c7c33 /]# cd home/
[root@5b402a1c7c33 home]# ls
[root@5b402a1c7c33 home]# touch my.java
[root@5b402a1c7c33 home]# ls
my.java
[root@5b402a1c7c33 home]# exit 
exit

对于容器内部的数据或者文件,无论他是否在运行,都存在计算机中,所以这里直接退出了。

#将容器中的文件拷贝出来
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker cp 5b402a1c7c33:/home/my.java /root
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# ls /root
demo-0.0.1-SNAPSHOT.jar  Dockerfile  my.java
  • 拷贝是一个手动过程,未来我们使用 -v卷的技术,可以实现,自动同步

小结

在这里插入图片描述

attach						#当前shell下attach连接指定运行镜像
buiTd						#通过Dockerfile定制镜像
commit 						#提交当前容器为新的镜像
cp							#从容器中拷贝指定文件或者目录到宿主机中
create						#创建一个新的容器,同run,但不启动容器
diff						#查看docker容器变化
events						#从docker:那务获取容器实时事件
exec						#在已存在的容器上运行命令
export 						#导出容器的内容流作为一个tar归档文件[对应 import]
history						#展示一个镜像形成历史
images                      #列出系统当前镜像
import 						#从tar包中的内容创建一个新的文件系统映像[对应export]
info						#显示系统相关信息
inspect						#查看容器详细信息
kill						#kill指定docker容器
load						#从一个 tar包中加载一个镜像[对应save]
login  						#注册或者登陆一个 docker 服务器
logout						#从当前Docker registry 退出
logs						#输出当前容器日志信息
port 						#查看映射端口对应的容器内部源端口
pause						#暂停容器
ps							#列出容器列表
pull 						#从docker镜像源服务器拉取指定镜像或者库镜像
push						#推送指定镜像或者库镜像至docker源服务器
restart						#重启运行的容器
rm							#移除一个或者多个容器
rmi							#移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或-f强制删除]
run							#创建一个新的容器并运行一个命令
save						#保存一个镜像为一个 tar 包[对应load]
search						#在docker hub中搜索镜像
start						#启动容器
stop						#停止容器
tag							#给源中镜像打标签
top							#查看容器中运行的进程信息
unpause						#取消暂停容器
version						#查看docker 版本号
wait						#截取容器停止时的退出状态值

练习

安装Nginx

docker search nginx
#拉取nginx镜像
docker pull nginx
#创建以一个nginx容器,-d后台运行,--name取个别名,-p指定端口映射
docker run -d --name nginx -p 8181:80 nginx

这里使用主机的8181端口映射容器中nginx的默认80端口,保证安全组打开:
在这里插入图片描述
在这里插入图片描述

#执行本机测试
curl localhost:8181

在这里插入图片描述
在这里插入图片描述

#进入容器
[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker exec -it 70988532f1b4 /bin/bash
root@70988532f1b4:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@70988532f1b4:/# ls /etc/nginx/
conf.d	fastcgi_params	koi-utf  koi-win  mime.types  modules  nginx.conf  scgi_params	uwsgi_params  win-utf

安装Tomcat

#我们之前的启动都是后台,停止了容器之后,容器还是可以查到docker run -it --rm,一般用来测试,用完及删除,只是删除容器,下载下来的镜像还在
#docker run -it --rm tomcat:9.0

#这里我们正常启动tomcat
docker run -d -p 9910:8080 tomcat

在这里插入图片描述

为什么404?

#进入容器
docker exec -it 564ad8f5f291 /bin/bash

在这里插入图片描述

因为阿里云的镜像默认是最小的,把所有没必要的都给删了,保证了最小运行环境

但是我们也可以解决这个404问题
在这里插入图片描述

cp -r webapps.dist/* webapps

在这里插入图片描述

可视化

  • portainer
docker run -d -p 9910:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

第一次进入很慢,打开后设置一个密码进入

在这里插入图片描述
在这里插入图片描述

选择本地local连接,连接成功以后就可以以图形化界面管理我们的docker

Docker镜像

什么是镜像

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。——所有的应用打包部署

  • 如何得到镜像
    • 从远程仓库下载
    • 朋友拷贝
    • 自己制作一个镜像Dockerfile

Docker镜像加载原理

UnionFS(联合文件系统)

UnionFS(联合文件系统) :Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS
bootfs (boot file system)主要包含bootloader(加载器)和kernel(内核), bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs

roots (root fle system),在boots之上。包含的就是典型Linux系统中的/dev, /proc, /bin,/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu ,Centos等等。
在这里插入图片描述

分层的理解

分层的镜像

我们下载镜像的时候都是一层一层的下载的

而分层的最大的好处就是莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

#查看镜像分层
docker inspect tomcat:9.0

在这里插入图片描述

#安装一个新的镜像
docker pull redis

在这里插入图片描述

  • 这里可以发现本地某一层已经下载了,就不会再下载了

理解

所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在这里插入图片描述
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
在这里插入图片描述
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。
在这里插入图片描述

特点

Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!这一层就是我们通常说的容器层,容器之下的都叫镜像层!
在这里插入图片描述

如何提交自己的镜像

docker commit 提交一个容器作为一个新的副本

docker commit -m="提交的信息" -a="作者" 容器id 目标镜像名[TAG]

例子:这里就以之前将tomcat容器为例,我们将webapps.dist中的文件都拷贝到webapps中。

#然后收将我们修改过的容器提交为一个新的镜像,以后就可以使用我们修改过后的新的镜像
docker commit -a="phz" -m="add webapps app" 376128031a30 tomcat02:1.0

在这里插入图片描述
如果你想要保存当前容器的状态,就可以通过commit来提交,-获得一个镜像,就好比我们以前学习VM时候,快照!

容器数据卷

什么是容器数据卷

docker的理念回顾

将应用和环境打包成一个镜像!
数据?如果数据都在容器中,那么我们容器删除,数据就会丢失,需求∶数据可以持久化

MySQL,容器删了,删库跑路,需求:MySQL数据可以存储在本地!
容器之间可以有一个数据共享的技术,Docker容器中产生的数据,同步到本地

这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面
在这里插入图片描述

总结:容器的持久化和同步操作

使用数据卷

命令

#docker run -it -v 主机目录:容器内部目录 -p

docker run -it -v /home/ceshi:/home centos /bin/bash

在这里插入图片描述
容器起来以后就会在本地home目录下面生成我们的ceshi文件夹

#查看一下这个容器的挂载情况
docker inspect 9ac9da1b4038

在这里插入图片描述

  • 来测试一下挂载
    在这里插入图片描述

此时容器内的home文件夹和主机内home\ceshi文件夹都没有数据,分别使用容器和主机新建文件
在这里插入图片描述
在这里插入图片描述
此时我们再把容器关掉,并在主机中修改hello文件内容
在这里插入图片描述
再启动容器
在这里插入图片描述
在这里插入图片描述
好处:我们以后修改只需要在本地修改即可,容器内会自动同步!

实验

创建一个mysql容器

docker run -d -p 9910:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql_test mysql:5.7

我们可以挂载多个文件目录,-e表示配置环境,这里表示给mysql配置一个初始密码,在使用navicat连接测试
在这里插入图片描述
在这里插入图片描述

可以看到挂载成功了,这里我们创建一个数据库test
在这里插入图片描述
发现挂载文件夹里面也更新了
在这里插入图片描述
即使我们把这个容器直接给干掉了,本地保存的文件还依然在
在这里插入图片描述

具名和匿名挂载
#匿名挂载
-v 容器内路径
docker run -d -p 9910:80 --name nginx01 -v /etc/nginx nginx 
#具名挂载
docker run -d -p 9910:80 --name nginx02 -v juming:/etc/nginx nginx
#查看所有卷(volume)的情况
docker volume ls

在这里插入图片描述

查看挂载目录

docker volume inspect juming#如果是匿名挂载就直接写他的volume name就可以了(就是很长的那个像id的东西,但不是id)

在这里插入图片描述
所有容器内的卷,如果没有指定目录的话,都是再/var/lib/docker/volumes/xxxxx/_data下面

拓展

ro				#read only,表示这个文件里面只能通过宿主机来修改,容器内部是不允许修改的
rw           	#read write
docker run -d -p 9910:80 -v juming:/etc/nginx:ro nginx
docker run -d -p 9910:80 -v juming:/etc/nginx:rw nginx

初识DockerFile

Dockerfile就是用来构建docker镜像的构建文件,命令脚本。

创建一个dockerfile文件,写入以下命令通过这个脚本可以生成镜像,注意都是大写

FROM centos
#匿名挂载
VOLUME ["volume01","volume02"]
CMD echo "------end--------id
CMD /bin/bash

保存退出,开始生成镜像

docker build -f dockerfile01 -t phz_centos .

在这里插入图片描述

进入这个镜像

在这里插入图片描述

发现这两个生成镜像的时候自动挂载的数据卷目录,那么他一定也会和外部某个目录与之同步

docker inspect ce1133572a72

在这里插入图片描述

为什么要在创建镜像的时候就挂载卷呢?

​ 假设我们在构建镜像的时候没有挂载卷,当我们需要创建容器的时候,就必须得一个个手动挂载卷

数据卷容器

  • 如果想要多个mysql同步数据呢?

]

实验:

​ 分别创建三个容器:

#父容器
docker run -it --name docker01 phz_centos
docker run -it --name docker02 --volumes-from docker01 phz_centos
docker run -it --name docker03 --volumes-from docker01 phz_centos

在这里插入图片描述

在父容器docker01中的数据卷目录创建文件

在这里插入图片描述

进入子容器docker02docker03分别确认以下数据卷有没有同步

在这里插入图片描述
只要通过这种方式共享数据卷,无论在父容器还是子容器中的数据卷目录中做什么,三者之间都是同步的

如果这里把docker01删除掉,共享的数据卷目录依然存在

  • 所以实现两个mysql之间数据同步,就可以:
#第一个
docker run -d -p 9910:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql_test01 mysql:5.7
#第二个
docker run -d -p 9910:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql_test02 --volumes-from mysql_test01 mysql:5.7

结论:容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器去使用它为止(所有依赖于该容器卷的容器都不存在了),但是一旦以持久化方式写入到了本地,本地的数据是不会删除的

Dockerfile

dockerfile介绍

dockerfile是用来构建dokcer镜像的文件,命令参数脚本。

构建步骤∶

1、编写一个dockerfile文件

2、docker build构建成为一个镜像

3、docker run运行镜像

4、docker push 发布镜像(DockerHub、阿里云镜像仓库!)
在这里插入图片描述

点击该镜像就会进入对应的GitHub仓库

在这里插入图片描述

所以我们发现,所谓的docker镜像,也就是由一个dockerfile来生成的,所以dockerfile就类似与一种源代码的味道

  • 很多官方镜像都是基础包,很多功能没有,我们通常会搭建自己的镜像

dockerfile构建过程

基础知识

1、每个保留关键字(指令)都是必须是大写字母

2、执行从上到下顺序执行

3、#表示注释

4、每一个指令都会创建提交一个新的镜像层,并提交!
在这里插入图片描述
在这里插入图片描述

dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件。

DockerFile :构建文件,定义了一切的步骤,源代码

Dockerlmages :通过DockerFile构建生成的镜像,最终发布和运行的产品!

dockerfile命令

docker hub99%的镜像都是由这个基础镜像过来的FROM scratch,然后配置来构建的

FROM					#基础镜镜像,一切从这里开始构建
MAINTAINER				#镜像是谁写的,姓名+邮箱
RUN						#镜像构建的时候需要运行的命令
ADD						#步骤:tomcat镜像,这个tomcat压缩包!添加内容
WORKDIR					#镜像的工作目录
VOLUME					#挂载的目录
EXPOSE					#暴露端口配置
CMD						#指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT				#指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD					#当构建一个被继承 DockerFile这个时候就会运行ONBUILD的指令。触发指令。
COPY					#类似ADD ,将我们文件拷贝到镜像中
ENV						#构建的时候设置环境变量!

在这里插入图片描述

创建一个自己的centos

创建mycentos文件

#基础镜像设置为centos
FROM centos 
#填写配置者的信息
MAINTAINER phz<1551402789@qq.com>

#配置一个自己的工作目录
ENV MYPATH /usr/local
WORKDIR $MYPATH

#下载vim编辑器(因为基础镜像里面没有vim),和net-tools,可以执行ifconfig命令
RUN yum -y install vim
RUN yum -y install net-tools

#对外暴露80端口
EXPOSE 80

#输出一些构建信息测试是否构建成功
CMD echo $MYPATH
CMD echo "------end-------"
CMD /bin/bash

通过这个文件构建镜像

docker build -f mycentos -t mycentos:1.0 .

这里本人操作的时候在下载vim的时候速度奇慢,感觉是某个地方没有配置阿里的源,从国外下载的,这里就不深入测试了

CMD和ENTRYPOINT区别

CMD						#指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT				#指定这个容器启动的时候要运行的命令,可以追加命令
  • 这里创建一个cmd测试dockerfile
FROM centos
CMD ["ls","-a"]
#构建
docker build -f mycmdtest -t cmdtest .

在这里插入图片描述

docker run cmdtest

在这里插入图片描述

这个时候如果想给这个容器追加一个命令

docker run cmdtest -l

在这里插入图片描述
所以这个地方就发现了cmd命令是不支持追加的,这里一个-l就会被视为将原有的ls -a替换为-l,而-l不是一个完整的命令所以会报错,所以可以像下面这样写

在这里插入图片描述

  • 这里创建一个ENTRYPOINT测试镜像
FROM centos
ENTRYPOINT ["ls","-a"]
docker build -f myentrypoint -t entrypointtest .

在这里插入图片描述
测试:
在这里插入图片描述
在这里插入图片描述

Tomcat镜像

先下载jdk

wget https://download.oracle.com/otn/java/jdk/8u271-b09/61ae65e088624f5aaa0b1d2d801acb16/jdk-8u271-linux-x64.tar.gz

再下载tomcat

wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-9/v9.0.40/bin/apache-tomcat-9.0.40.tar.gz

在这里插入图片描述

编写Dockerfile(官方指定命名方法,这样写的话就不用指定文件名-f,可以自动识别)

FROM centos
MAINTAINER phz<1551402789@qq.com>

COPY readme.txt /user/localreadme.txt

ADD apache-tomcat-9.0.40.tar.gz /usr/local
ADD jdk-8u271-linux-x64.tar.gz /usr/local

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_271
ENV CLASS_PATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.40
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.40
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.40/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.40/bin/logs/catalina.out

构建容器

docker build -t mytomcat .

在这里插入图片描述

开始创建我们的tomcat

docker run -d -p 9910:8080 --name mytomcat -v /home/dockerfile-test/tomcatDockerfile/test:/usr/local/apache-tomcat-9.0.40/webapps/test -v /home/dockerfile-test/tomcatDockerfile/tomcatlogs:/usl/local/apache-tomcat-9.0.40/logs mytomcat

测试
在这里插入图片描述
创建tomcat的时候为什么要挂载我们本地文件夹呢,就是因为这样我们就可以不用进入容器就可以发布项目了

手写一个网站

  • 进入这个容器的tomcat工作目录,我们之前创建了一个test文件夹,在里面创建两个文件:
    在这里插入图片描述
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hello</title>
</head>
<body>
hello word
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">

</web-app>
  • 保存退出即可
    在这里插入图片描述

将我们的镜像发布

Docker hub

首先当然是注册一个账号

再然后就是登录

docker login -u xxx -p xxx

在这里插入图片描述

提交镜像的时候必须保证镜像名称符合规范

#修改镜像tag,dockers hub账号/镜像名称
docker tag demo:latest 19990910/springboot

然后执行push指令

docker push 19990910/springboot

在这里插入图片描述

阿里云镜像仓库

打开阿里云服务器控制面板

在这里插入图片描述

创建命名空间

在这里插入图片描述

创建镜像仓库

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

点击进入
在这里插入图片描述

登录阿里云镜像

sudo docker login --username=cestbon_phz registry.cn-beijing.aliyuncs.com

在这里插入图片描述

修改符合阿里云镜像仓库命名规则的tag

sudo docker tag cestbon_phz/springboot:latest registry.cn-beijing.aliyuncs.com/phz_images_test/test_01:1.0

在这里插入图片描述

执行push指令

sudo docker push registry.cn-beijing.aliyuncs.com/phz_images_test/test_01:1.0

小结

在这里插入图片描述

Docker网络

在这里插入图片描述
在这里插入图片描述

开启一个tomcat容器,然后进入查看当前容器内部网络信息

docker exec -it mytomcat ip addr

#eth0这个网络地址就是docker自动分配的
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

172.17.0.2/16 这里的16表示这32位地址中,高16位作为一个内网,剩下的16位为域内地址

docker network inspect 容器id

在这里插入图片描述

我们直接ping这个网络地址,看看能不能ping

ping 172.17.0.2

在这里插入图片描述

我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0,我们的docker采用的是桥接模式,使用的技术是evth-pair技术

在这里插入图片描述

再次查询本机网络信息,发现多了一个网卡,而且这个网卡与docker内部获得的网络信息中的网卡很相似,且名称是成对的

在这里插入图片描述

再次启动一个新的tomcat

在这里插入图片描述

再次测试本机的网络信息,发现也多了一个

在这里插入图片描述
所以我们发现,我们的容器所带来的网卡,都是成对成对的出现的,而原因就是因为evth-pair技术,它就是一对虚拟的网卡,一端连着协议,一端彼此相连

正因为有这个特性,evth-pair充当一个桥粱,连接各种虚拟网络设备,openstacDocker容器之间的连接,0VS的连接,都是使用evth-pair 技术

测试这里的两个tomcat是否能够ping通,结果理所当然的是能啊

在这里插入图片描述

总结

在这里插入图片描述
为什么docker要用虚拟的网桥呢?因为转发快,当我们把容器删除后,对应的那一对网桥也就自动删除了

思考一个问题,我们做微服务的时候,某个服务的ip更换掉了,我们希望跟他有关系的服务不被影响,直接通过名字访问容器可以吗?

–link

这里启动两个tomcat

docker run -d -p --name mytomcat tomcat
docker run -d -p --name mytomcat01 tomcat

尝试直接通过名称来ping,发现ping不通,但是我们是可以解决这个问题的

docker exec -it mytomcat ping mytomcat01

[root@iZ2ze5wj5w33v3gyd9kv1bZ ~]# docker exec -it mytomcat ping mytomcat01
ping: mytomcat01: Name or service not known

我们再启动一个tomcat镜像

docker run -d -P --name mytomcat02 --link mytomcat01 tomcat

尝试使用mytomcat02直接通过名称ping mytomcat01,发现是成功的

docker exec -it mytomcat02 ping mytomcat01

在这里插入图片描述

但是我们反向ping会发现ping不通,也就是这样配置还只是单向的

探究mytomcat02hosts文件,发现,我们的mytomcat01ip被写死在里面了,当然是可以ping

docker exec -it mytomcat02 cat /etc/hosts

在这里插入图片描述

我们再去看一下01,自然而然是没有

在这里插入图片描述
但是真实开发不建议–link,我们很多地方的自定义网络,不支持docker0,因为它不支持容器名来ping

自定义网络

查看所有的docker网络

docker network ls

在这里插入图片描述

网络模式

bridge:桥接 docker(默认,自己定义网络也用桥接)

null:不配置网络

host:和宿主机共享网络

container:docker容器内网络连通(很少使用)

#以前启动没写--net bridge,因为这是docker默认的方式,即docker0
#docker0特点:默认,不能通过域名访问,--link可以打通连接
docker run --name tomcat01 -P -d --net bridge tomcat

自定义网络测试

#192.168.0.0/16表示最多支持255*255个网络,如果时192.168.0.0/24就只能支持255个网络,192.168.0.1 - 192.168.1.254
#192.168.0.1表示网关地址,通往其他网段的请求都会经过它,除了网络地址,广播地址以外的可用主机地址都可以分配给他
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

在这里插入图片描述
在这里插入图片描述

使用我们自己定义的网络创建tomcat容器

docker run -d -P --name mynet-tomcat01 --network mynet  tomcat
docker run -d -P --name mynet-tomcat02 --network mynet  tomcat

在这里插入图片描述

这个时候我们通过ip和容器名来分别ping试试能不能ping通,结果是可以!

docker exec -it mynet-tomcat01 ping 192.168.0.2
#不使用--link照样能够ping通
docker exec -it mynet-tomcat01 ping mynet-tomcat02

在这里插入图片描述
我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络

好处∶

redis -不同的集群使用不同的网络,保证集群是安全和健康的

mysql -不同的集群使用不同的网络,保证集群是安全和健康的

网络联通

思考
在这里插入图片描述
结论自然是不能的,因为他们本身就处在不同的网段中

查看docker network --help帮助,发现有个connect

在这里插入图片描述
在这里插入图片描述

测试

#创建两个docker默认网络的tomcat
docker run -d -P --name docker0-tomcat01 tomcat
docker run -d -P --name docker0-tomcat02 tomcat

测一下吧,虽然肯定不行

在这里插入图片描述

打通网络和容器

docker network connect mynet docker0-tomcat01
docker network connect mynet docker0-tomcat02

再次测试

docker exec -it mynet-tomcat01 ping docker0-tomcat01

在这里插入图片描述

查看mynet网络信息

在这里插入图片描述

本质就是将docker0-tomcat0102放到了mynet下面,也就是一个容器两个ip,就好比阿里云服务器,一个公网ip一个内网ip

Redis部署集群实战

停止所有运行的容器

docker stop $(docker ps -aq)

移除之前创建的网络

docker network rm mynet

创建我们的redis集群网络

docker network create redis --subnet 172.38.0.0/16

在这里插入图片描述

编写shell脚本,批量配置redis服务

for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

在这里插入图片描述

查看配置文件

在这里插入图片描述

修改本地redis配置文件,开启集群部署

在这里插入图片描述

再次批量拉取redis镜像并启动redis服务

#redis1
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

#redis2
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

#redis3
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

#redis4
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
-v /mydata/redis/node-4/data:/data \
-v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

#redis5
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
-v /mydata/redis/node-5/data:/data \
-v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

#redis6
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/redis/node-6/data:/data \
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

在这里插入图片描述

进入redis容器配置主从复制,注意redis镜像没有bash命令,应该是sh命令

docker exec -it redis-1 /bin/sh

redis集群部署连接各个redis服务

redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1

在这里插入图片描述

输入yes

完成后连接测试

redis-cli是单机,要-c表示集群

redis-cli -c

进入redis服务查看集群节点信息

cluster info
cluster nodes

在这里插入图片描述

设置一个key,发现是13这个主机节点处理的请求,那么他的从机自然也就能够获取到值

127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK

这个时候我们把主机13这个主机停了,看看a这个值能否正常获取

docker stop redis-3

然后我们再次获取以下a值,我这个地方是退出命令行重新进入redis-cli -c的,不退就一直给我提示无法连接到13,虽然本来就连不上。

在这里插入图片描述

所以我们发现这个a14获取到了,就是因为14代替了13成为了主机

再次查看节点信息

在这里插入图片描述
发现原来的13出现了故障,但是转移了,14成为master!!

Docker compose

什么是Docker compose

官方文档

一次性定义,运行多个容器,解决集群部署的时候,大量容器部署的问题。

开发步骤

Using Compose is basically a three-step process:

  1. Define your app’s environment with a Dockerfile so it can be reproduced anywhere.(编写Dockerfile)
  2. Define the services that make up your app in docker-compose.yml so they can be run together in an isolated environment.(编写docker-compose.yml配置文件)
  3. Run docker-compose up and Compose starts and runs your entire app.(启动docker-compose)

docker-compose.yml文件官方示例

version: "3.8"
#一个集群中的多个服务
services:
  #web服务
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
      - logvolume01:/var/log
    #因为需要连接到redis,这里定义了links就需要先启动redis,docker compose自动识别启动顺序
    links:
      - redis
  #redis服务
  redis:
    image: redis
volumes:
  logvolume01: {}

compose的一些重要概念

  • 服务services:容器,应用,(webredismysql…)
  • 项目project:一组关联的容器

未来上线项目,不会简单的使用docker上线,肯定是需要docker compose的,但是docker compose还只是单机范围内部署,未来的集群还得docker swarm

安装

官方下载

sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

有时候官方连接下载不是很快,如果下载缓慢,可以使用国内下载地址

curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

在这里插入图片描述

给该文件开启可执行权限

chmod +x /usr/local/bin/docker-compose

查看docker-compose版本

docker-compose version

在这里插入图片描述

快速体验,官方提供快速开始的python使用redis计数的一个应用

  • 第一步,创建测试文件夹
mkdir composetest
cd composetest
  • 第二步,编写python文件app.py
import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\n'.format(count)
  • 第三步,创建导入的依赖包requirements.txt
flask
redis
  • 第四步,编写一个Dockerfile
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
  • 第五步,创建docker-compose.yml配置文件

注意yml文件严格注意格式,":“和”-"后面都必须跟上一个空格,如果语法报错,建议手敲

version: "3.8"
services:
    web:
        build: .
        ports:
            - "5000:5000"
    redis:
        image: "redis:alpine"
  • 第五步,开启docker-compose,第一次部署这个集群,会下载一些东西,这个过程略微有些缓慢,也就等了一个小时吧
 docker-compose up

未完。。。。。。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐