51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Docker总结(命令、镜像、容器、数据卷、DockerFile、网络、Compose)

文章已同步至掘金:https://juejin.cn/post/6896027012410900488
欢迎访问😃,有任何问题都可留言评论哦~

Docker常用命令 {#docker%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4}

帮助命令 {#%E5%B8%AE%E5%8A%A9%E5%91%BD%E4%BB%A4}

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

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

镜像命令 {#%E9%95%9C%E5%83%8F%E5%91%BD%E4%BB%A4}

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

[root@FanJunyang /]# docker images
REPOSITORY
hel1o-world

TAG
latest


IMAGE ID
bf756fb1ae65


CREATED
4 months ago


SIZE
13.3kB


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

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

docker search 搜索镜像

docker search mysql

可选项,搜索过滤
========



--filter=STARTS=3000	# 过滤星数不少于3000的

`docker search mysql --filter=STATRS=3000
`

docker pull 下载镜像

# docker pull 镜像名[:tag]
# 如果不写tag,默认就是latest(最新版)

指定版本下载
======


`docker pull mysql:5.7	# 必须官网上有
`

docker rmi 删除镜像

[root@FanJunyang /]# docker rmi -f 容器id #删除指定的容器
[root@FanJunyang /]# docker rmi -f 容器id容器id容器id容器id # 删除多个容器
[root@FanJunyang /]# docker rmi -f $(docker images -aq) # 删除全部的容器

容器命令 {#%E5%AE%B9%E5%99%A8%E5%91%BD%E4%BB%A4}

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

docker pull centos

新建容器并启动

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

测试,启动并进入容器
==========



docker run -it centos /bin/bash


ls # 查看容器内的centos,与外界的已隔离开


列出所有的运行的容器

docker ps 
   #列出当前正在运行的容器
-a #列出当前正在运行的容器+带出历史运行过的容器
-n=? #显示最近创建的容器
-q #只显示容器的编号
`举例:
docker ps -aq
`

退出容器

exit # 直接容器停止并退出  
Ctrl + P + Q # 容器不停止退出

删除容器

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 # 强制停止当前容器

常用其他命令 {#%E5%B8%B8%E7%94%A8%E5%85%B6%E4%BB%96%E5%91%BD%E4%BB%A4}

后台启动容器

#命令docker run -d 镜像名
[root@FanJunyang /]# docker run -d centos
#问题docker ps,发现centos停止了
# 常见的坑, docker容器使用后台运行,就必须要有要一个前台进程, docker发现没有应用,就会自动停止
# nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了

查看日志

docker logs

docker logs -f -t --tail 容器id,没有日志


docker logs --help # 查看帮助


#自己编写一段she11脚本
\[root@FanJunyang /# docker run -d centos /bin/sh-c "while true; do echo kuangshen;sleep 1;done"
#\[root@FanJunyang /\]# docker ps
CONTAINER ID
dce7b86171bf


IMAGE
centos


显示日志
====


`-tf		# 显示日志
--tail number # number要显示日志条鼓
[root@FanJunyang /]# docker logs -tf --tail 10 dce7b86171bf
`

查看容器中的进程信息

docker top 容器id

查看镜像的元数据

docker inspect 容器id

进入当前正在运行的容器

#我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置
# 方式一
docker exec -it 容器id /bin/bash

方式二
===



docker attach 容器id


正在执行当前的代码
=========



docker exec 进入容器后开启一个新的终端,可以在里面操作(常用)
=====================================



docker attach 进入容器正在执行的终端,不会启动新的进程!
===================================



注:不管容器有没有启动,拷贝命令都是生效的

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

docker cp 容器id:容器内路径 目的的主机路径

测试
===


`docker cp 容器id:/home/test.js /home
`

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

docker cp 主机路径/文件名 容器名(或者id):容器路径  

小结 {#%E5%B0%8F%E7%BB%93}

attach --> Attach to a running container # 当前shell下attach连接指定运行镜像
build --> Build an image from a Dockerfile #通过Dockerfile定制镜像
commit --> create a new image from a container changes #提交当前容器为新的镜修
cp --> Copy files/folders from the containers filesystem to the host path #从容器中拷贝指定文件或者目录到宿主机中
create --> Create a new container #创建一个新的容器,同run,但不启动容器
diff --> Inspect changes on a container's filesystem #查看docker容器变化
events --> Get real time events from the server #从 docker服务获取容器实时事件
exec --> Run a command in an existing container #在已存在的容器上运行命令
export --> stream the contents of a container as a tar archive #导出容器的内容流作为一个tar归档文件[对应import]
history --> show the history of an image #展示一个镜像形成历史
images --> List images #列出系统当前镜像
import --> Create a new filesystem image from the contents of a tarbal1 #从tar包中的内容创建一个新的文件系统映像[对应export]
info --> Display system-wide information #显示系统相关信息
inspect --> Return low-level information on a container #查看容器详细信息
kill --> kill a running container #kil1指定docker容器
load --> Load an image from a tar archive #从一个tar包中加载一个镜像[对应save]
login --> Register or Login to the docker registry server #注册或者登陆一个docker源服务器
logout --> Log out from a Docker registry server #从当前Docker registry退出
logs --> Fetch the logs of a container #输出当前容器日志信息
port --> Lookup the public-facing port which is NAT-ed to PRIVATE-PORT #查看映射端口对应的容器内部源端口
pause --> Pause all processes within a container #暂停容器
ps --> List containers #列出容器列表
pull --> Pull an image or a repository from the docker registry server #从docker镜像源服务器拉取指定镜像或者库镜像
push --> Push an image or a repository to thel docker registry server #推送指定镜像或者库镜像至docker源服务器
restart --> Restart a running container #重启运行的容器
rm --> Remove one or more containers #移除一个或者多个容器
rmi --> Remove one or more images #移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或-f 强制删除]
run --> Run a command in a new container #创建一个新的容器并运行一个命令
save --> Save an image to a tar archive #保存一个镜像为一个tar包[对应1oad]
search --> Search for an image on the Docker Hub #在docker hub 中搜索镜像
start --> Start a stopped containers #启动容器
stop --> Stop a running containers #停止容器
tag --> Tag an image into a repository #给源中镜像打标签
top --> Lookup the running processes of a container #查看容器中运行的进程信息
unpause --> Unpause a paused container #取消暂停容器
version --> Show the docker version information #查看docker版本号
wait --> B1ock until a container stops, then print its exit code #截取容器停止时的退出状态值

部署Tomcat {#%E9%83%A8%E7%BD%B2tomcat}

#官方的使用
docker run -it --rm tomcat:9.0
#我们之前的启动都是后台,停止了容器之后,容器还是可以查到 docker run -it --rm,一般用来测试,用完就删除容器

#下载在启动
docker pull tomcat


#启动运行
docker run -d -p 3355:8080 --name tomcat01 tomcat


#测试是不行的,下面说原因


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


#发现问题: 1.1inux命令少, 2,webapps里面没有内容. 阿里云镜像的原因。默认是最小的镜像,所有不必要的都剔除掉。
#保证最小可运行的环境!


#这时候你会发现一个webapps.dist目录,进去查看,发现里面有所需要的文件,直接返回上一级,把所需的文件复制到webapps里面即可
cp -r webapps.dist/\* webapps


#然后进入tomcat的bin目录下,启动tomcat即可,命令:./startup.sh

`#重新访问即可成功
`

可视化 {#%E5%8F%AF%E8%A7%86%E5%8C%96}

  • portainer(先用这个)
docker run -d -p 8088:9000\
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
  • Rancher(CI/CD再用)

什么是portainer?

Docker图形化界面管理工具!提供一个后台面板供我们操作!

commit镜像 {#commit%E9%95%9C%E5%83%8F}

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

命令和git原理类似
==========



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


测试命令
====


`docker commit -a="fanjunyang" -m="add webapps app" 7e119b65d6gd5 tomcat02:1.0
`

#1、启动一个默认的tomcat
#2、发现这个默认的tomcat是没有webapps应用, 镜像的原因,官方的镜像默认webapps下面是没有文件的!
#3、我自己拷贝进去了基本的文件
#4、将我们操作过的容器通过commit提交为一个镜像!我们以后就使用我们修改过的镜像即可,这就是我们自己的一个修改的镜像

容器数据卷 {#%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7}

什么是容器数据卷? {#%E4%BB%80%E4%B9%88%E6%98%AF%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7%3F}

docker的理念回顾
将应用和环境打包成一个镜像!
数据?如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化
MySQL,容器删了,删库跑路!需求: MySQL数据可以存储在本地!
容器之间可以有一个数据共享的技术! Docker容器中产生的数据,同步到本地!
这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面!

总结一句话:容器的持久化和同步操作!容器间也是可以数据共享的!

使用数据卷 {#%E4%BD%BF%E7%94%A8%E6%95%B0%E6%8D%AE%E5%8D%B7}

方式一:直接使用命令来挂载 -v

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

测试
===



\[root@FanJunyang home\]# docker run -it -v /home/ceshi:/home centos /bin/bash

`#启动起来时候我们可以通过docker inspect 容器id查看Mounts挂载关系
`

好处:我们以后修改只需要在本地修改即可,容器内会自动同步!

如果删除容器,那么同步的文件夹并不受影响,宿主机上依然有!

实战:安装MySQL {#%E5%AE%9E%E6%88%98%3A%E5%AE%89%E8%A3%85mysql}

思考: MySQL的数据持久化的问题

# 获取镜像
[root@FanJunyang home]# docker pull mysq1:5.7
#运行容器,需要做数据挂载! #安装启动mysq1 ,需要配置密码的,这是要注意点!
#官方测试: docker run --name some-mysql -e MYSQL_ROOT_PASSWORD-my-secret-pw -d mysql :tag

注意一个点,最好先进入容器,把/etc/mysql/conf.d这个文件备份一下,防止同步数据时,数据丢失
-----------------------------------------------------



#启动我们的
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
--name 容器名字
\[root@FanJunyang home\]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/1ib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysq101 mysq1:5.7


#启动成功之后,我们在本地使用sqlyog或者Navicat来接测试一下
#Navicat-连接到服务器的3310 -- 3310和容器内的3306映射,这个时候我们就可以连接上了!


接着看下自己宿主机上的 /home/mysql/data,应该是空的,因为暂时没有数据库,接着我们用Navicat创建一个数据库,接着再查看data这个文件夹,发现有数据了,则现在一切正常
==============================================================================================



假如我们将容器删除,发现我们挂载到本地的数据卷的数据依然没有丢失,这就实现了容器数据持久化功能!

具名和匿名挂载 {#%E5%85%B7%E5%90%8D%E5%92%8C%E5%8C%BF%E5%90%8D%E6%8C%82%E8%BD%BD}

#匿名挂载
-v 容器内路径
docker run -d -p --name nginx01 -v /ect/nginx nginx
# 查看所有的volume的情况
docker volume 1s

local 		9f38292179faa178afcce54d80be99d4ddd68c91d2a68870bcece72d2b7ed061
#这里发现,这种就是匿名挂载,我们在-v只写了容器内的路径,没有写容器外的路径!


#具名挂载
docker run -d -p--name nginx02 -v juming-nginx:/etc/nginx nginx


docker volume ls


DRIVER		VOLUME NAME
local		juming-nginx


通过 -v 卷名:容器内路径
==============



查看一下这个卷
=======



docker volume inspect juming-nginx


可以获得所有的信息
=========



所有的docker容器内的卷,没有指定目录的情况下都是在 var/docker/volumes/xxxx/_data
==========================================================



我们通过具名挂载可以方便的找到我们的每一个卷,大多数情况在使用的是 具名挂载
======================================



# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载!
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载!

扩展:

# 通过 -v 容器内路径:ro rw 改变读写权限
ro  readonly	# 只读
rw	readwrite	# 可读可写

#一旦设置了容器权限,容器对我们挂载出来的内容就有限定了!
docker run -d -p --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -p --name nginxo2 -v juming-nginx:/etc/nginx:rw nginx

`#ro只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作!
`

初始Dockerfile {#%E5%88%9D%E5%A7%8Bdockerfile}

Dockerfile就是用来构建docker镜像的构建文件!

他是命令脚本!

先体验一下!
通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层!

#可以在home下创建一个docker-test-volume文件夹,用来存放我们的测试文件,接着创建一个dockerfile文件,名字可以随机,建议Dockerfile
#文件中的内容指令(大写) 参数
FROM centos
VOLUME ["volume01", "volume02"]
CMD echo "--end--"
CMD /bin/bash
`#这里的每个命令,就是镜像的一层!
`

#生成镜像(在docker-test-volume文件夹下)
docker build -f Dockerfile1 -t fan_centos .

# docker build -f Dockerfile1 -t fan_centos:1.0 .	# 也可以跟上版本

-f	# 指的file的地址
-t	# 指生成的文件名
# 最后的一个点别忘了,指在当前目录下生成

docker images	# 看下自己创建的镜像

使用自己创建的镜像启动一个容器后docker run -it fan_centos /bin/bash,发现根目录下有volume01和volume02两个文件夹。

这个卷(文件夹)和外部肯定有同步的文件夹,这种方式挂载默认是匿名挂载,可以使用docker inspect 容器id自己查看下Mounts

测试一下刚才的文件是否同步出去了!
这种方式我们末来使用的十分多,因为我们通常会构建自己的镜像!
假设构建镜像时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径!

数据卷容器 {#%E6%95%B0%E6%8D%AE%E5%8D%B7%E5%AE%B9%E5%99%A8}

需求:多个容器同步数据!(可以使用 --volumes-from

docker-command-3

# 根据上面创建的镜像,我们先跑一个容器(docker01):  

docker run -it --name docker01 fan_centos


接着再跑一个容器(docker02),继承了docker01:
===============================



docker run -it --name docker02 --volumes-from docker01 fan_centos


然后我们在docker01容器中volume01文件夹中新建一个文件,接着在docker02容器中查看volume01文件夹,发现其中数据已经同步了
==========================================================================



docker01创建的内容同步到了docker02上面
===========================



注意:同步是双向的,无论在哪个容器中操作文件,那么其他容器也会同步数据

# 如果docker02和docker03同时继承docker01,那么如果删除docker01,那么docker02和docker03容器中的内容会删除吗?

答:依旧可以访问(拷贝的概念,相当于硬链接)
======================



实操:多个mysql实现数据共享

docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql

docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql


这个时候,可以实现两个容器数据同步
=================



结论:
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!

DockerFile {#dockerfile}

dockerfile是用来构建docker镜像的文件! 命令參数脚本!

构建步骤:

  1. 编写一个dockerfile文件

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

  3. docker run运行镜像

  4. docker push发布镜像( DockerHub、阿里云镜像仓库)

DockerFile构建过程 {#dockerfile%E6%9E%84%E5%BB%BA%E8%BF%87%E7%A8%8B}

基础知识:
1、每个保留关键字(指令)都必须是大写字母
2、执行从上到下顺序执行
3、#表示注释
4、每一个指令都会创建提交一个新的镜像层,并提交

docker-command-4

dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!

Docker 镜像逐渐成为企业交付的标准,必须要掌握!

DockerFile:构建文件,定义了一切的步骤,相当于就是源代码

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

Docker容器:容器就是镜像运行起来提供的服务器

DockerFile的指令 {#dockerfile%E7%9A%84%E6%8C%87%E4%BB%A4}

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

实战测试 {#%E5%AE%9E%E6%88%98%E6%B5%8B%E8%AF%95}

DockerHub中99%镜像都是从这个基础镜像过来的FROM scratch ,然后配置需要的软件和配置来进行的构建

创建一个自己的centos

# 1、编写Dockerfile的文件
[root@FanJunyang dockerfile]# cat mydockerfile-centos
FROM centos
MAINTAINER fanjunyang<996597002@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash

2、通过这个文件构建镜像
============



#命令 docker build -f dockerfile文件路径 -t 镜像名:\[tag\]
successfully built e2bd75cfe070
successfully tagged mycentos:0.1


3、测试运行
======



通过docker history 镜像id,可以查看整个镜像构建过程

CMD 和 ENTRYPOINT 区别

CMD	#指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代,
ENTRYPOINT #指定这个容器启动的时候要运行的命令,可以追加命令

测试cmd

# 编写dockerfile文件
FROM centos
CMD ["ls","-a"]

构建镜像
====



docker build -f dockerfile-cmd-test -t cmdtest .


run运行,发现我们的ls -a命令生效
====================



现在我们想追加一个 -l 命令 也就是 ls -al
==========================



docker run dd52asder6sd2 -l


发现报错
====



我们只好写完整
=======


`docker run dd52asder6sd2 ls -al
`

如果使用ENTRYPOINT,则直接可以追加,不会替换

FROM centos
ENTRYPOINT ["ls","-a"]

重新构建一个镜像,测试后可以追加
================



实战:Tomcat镜像 {#%E5%AE%9E%E6%88%98%3Atomcat%E9%95%9C%E5%83%8F}

  1. 准备镜像文件,tomcat,jdk压缩包

  2. 编写Dockerfile文件

FROM centos
MAINTAINER fanjunyang<996597002@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u11-1inux-x64.tar.gz /usr/1ocal/
ADD apache-tomcat-9.0.22.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/idk1.8.011
ENV CLASSPATH $JAVA HOME/1ib/dt.jar:$JAVA_HOME/1ib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.22
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.22
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/1ib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.22/bin/startup.sh && tail -F /usr/1ocal/apache-tomcat-9.0.22/bin/logs/catalina.out
  1. 构建镜像
docker build -t diytomcat .
  1. 启动容器(可以直接做卷挂载)
  2. 访问测试
  3. 发布项目

以后开发的步骤:需要掌握Dockerfile的编写,我们之后的一切都是使用docker镜像来发布运行

发布自己的镜像 {#%E5%8F%91%E5%B8%83%E8%87%AA%E5%B7%B1%E7%9A%84%E9%95%9C%E5%83%8F}

DockerHub

  1. 注册自己的账号
  2. 确定这个账号可以登录
  3. 在我们的服务器上提交自己的镜像
# 先在服务器上登录
docker login --help # 自己查看参数登录  
  1. 登录完毕后就可以提交镜像了,只有一步
docker push fanjunyang/镜像名:[tag]

给镜像加tag
=======



docker tag 镜像ID 名称(例如:fanjunyang/tomcat):\[tag\]


自己发布的时候尽量带上版本号(tag)
===================



阿里云镜像服务上

  1. 登录阿里云
  2. 找到容器鏡像服务
  3. 创建命名空间
  4. 创建容器镜像
  5. 浏览阿里云仓库信息(有具体步骤)

Docker网络 {#docker%E7%BD%91%E7%BB%9C}

理解Docker0 {#%E7%90%86%E8%A7%A3docker0}

三个网络

docker-command-5

问题:docker是如何在容器之间进行网络访问的?(例如:tomcat访问mysql)

测试:

# 启动一个容器  
docker run -d -p 3355:8080 --name tomcat01 tomcat

查看容器的内部网络地址 ip addr , 发现容器启动的时候会得到一个eth0@if262 ip地址, docker分配的!
===============================================================



docker exec -it tomcato1 ip addr


思考. liunx能不能ping通容器内部!
======================



\[root@FanJunyang /\]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq-1 tt1-64 time=0.067 ms
64 bytes from 172.18.0.2: icmp_seq-2 tt1-64 time=0.055 ms


linux可以ping通docker容器内部
======================



原理

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

再次测试 ip addr,发现多了一对网卡

2、再启动一个容器(tomcat02)测试,发现又多了一对网卡。

# 我们发现这个容器带来网卡,都是一对对的
# evth-pair就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性, evth-pair充当一个桥梁,连接各种虚拟网络设备的
# Openstac. Docker容器之间的连接, ovs的连接,都是使用evth-pair技术

3、测试下tomcat01和tomcat02能不能ping通?

docker exec -it tomcat02 ping 172.18.0.2

结论,容器和容器之间是可以互相ping通的
=====================



图例:

docker-command-1

结论: tomcat01和tomcat02是公用的一个路由器, docker0

所有的容器不指定网络的情况下,都是docker0路由的, docker会给我们的容器分配一个默认的可用IP。

小结

Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥docker0

docker-command-2

Docker中的所有的网络接口都是虚拟的。虚拟的转发效率高。

只要容器删除,对应的一对网桥就没了!

容器互联--link {#%E5%AE%B9%E5%99%A8%E4%BA%92%E8%81%94%E2%80%93link}

思考一个场景,我们编写了一个微服务, database url=ip:,项目不重启,数据库ip换掉了,我们希望可以处理这个问题,可以用名字来进行访问容器?

# 启动两个容器 tomcat01 tomcat02  

ping测试
======



dockerexec -it tomcat02 ping tomcat01


发现ping不通
========



如何解决?我们再新启动一个容器tomcat03连接tomcat02
=================================



docker run -d -P --name tomcat03 --link tomcat02 tomcat


通过--link,就可以解决了网络连通问题
=====================



反向可以ping通吗? 答:不可以
=================



其实就是这个tomcat03在本地配置了tomcat02的配置(在tomcat03的/etc/hosts文件中)
========================================================



本质:--link就是我们在hosts配置中增加了一个tomcat02的映射

我们现在玩Docker已经不建议使用--link !

自定义网络!不适用dockero0!

docker0问题:他不支持容器名连接访问!

自定义网络 {#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BD%91%E7%BB%9C}

查看所有的docker网络

docker network ls

网络模式:

  • bridge:桥接 docker(默认)
  • none:不配置网络
  • host:和宿主机共享网络
  • container:容器网络连通(用的少,局限很大)

测试

# 我们直接启动的命令,默认就加上参数 --net bridge,而这个就是我们的docker0

docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat


docker0特点:默认,域名不能访问,--link可以打通连接(不用)
====================================



我们可以自定义一个网络
===========



--driver bridge (桥接)
====================



--subnet 192.168.0.0/16 (子网地址)
==============================



--gateway 192.168.0.1 (网关)
==========================



docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet


查看
===



docker network ls


docker network inspect mynet


使用自己的网络创建容器
===========



docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat


再次测试ping连接
==========



docker exec -it tomcat-net-01 ping tomcat-net-02


发现可以ping通,不使用--link,也可以ping名字
=============================



我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络!

好处:

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

网络连通 {#%E7%BD%91%E7%BB%9C%E8%BF%9E%E9%80%9A}

上面已经说了,可以自己自定义网络,那么两个网络之间是互不连通的,所以两个网络之间的容器肯定是ping不通的。

现在我们使用connect可以解决这个问题(通过docker network --help查看参数)

# 结构
docker network connect [OPTIONS] NETWORK CONTAINER  

启动一个tomcat01
============



docker run -d -P --name tomcat01 tomcat


测试ping tomcat-net-01,ping不通
===========================



测试打通 tomcat01 - mynet
=====================



docker network connect mynet tomcat01


连通之后就是将 tomcat01 放到了 mynet 网络下
==============================



一个容器两个ip地址,就相当于阿里云服务,一个公网ip,一个私网ip
==================================



结论

假设要跨网络操作别人,就需要使用docker network connect连通...

Docker Compose {#docker-compose}

简介 {#%E7%AE%80%E4%BB%8B}

缺点:DockerFile build run手动操作,1单个容器!

如果要管理100个微服务,累死。

Docker Compose可以用来轻松高效的管理容器,定义运行多个容器。

  • 定义、运行多个容器
  • YAML file配置文件
  • 命令有哪些?
  • 所有的环境都可以使用Compose

作用:批量容器编排

Compose :重要的概念

  • 服务services,。容器。应用.(web, redis, mysq...)
  • 项目project。一组关联的容器。(博客:web, mysql)

安装 {#%E5%AE%89%E8%A3%85}

地址:https://docs.docker.com/compose/install/

  1. 下载
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
  1. 授权
sudo chmod +x /usr/local/bin/docker-compose

如果报错或失败,那可能是你没下载成功,这时最好去官网,先把包下载下来

官网地址

docker-command-6

下载下来后,放到你系统中的这个位置:

docker-command-7

接着改一下文件名,然后重新提升下权限就可以了。

体验 {#%E4%BD%93%E9%AA%8C}

地址:https://docs.docker.com/compose/gettingstarted/

步骤

  1. 应用 app.py
  2. Dockerfile应用打包为镜像
  3. Docker-compose yaml文件(定义整个服务,需要的环境, web, redis)完整的上线服务
  4. 启动compose项目(docker-compose up)

docker-compose

以前都是单个docker run启动容器.

docker-compose。通过docker-compose编写yaml配置文件、可以通过compose一键启动、停止所有服务。

Docker小结:

  1. Docker鏡像. run =>容器
  2. Dockerfile构建镜像(服务打包)
  3. docker-compose启动项目(编排、多个微服务/环境)
  4. Docker网络!

yaml规则 {#yaml%E8%A7%84%E5%88%99}

docker-compose.yaml 核心文件

地址:https://docs.docker.com/compose/compose-file/

#3层!
version:.版本
services:  服务
	服务1: web	
		# 服务配置
		images
		build
		network
		...
	服务2: redis
		...
	服务3: redis
# 其他配置网络/卷、全局规则
volumes:
networks:
configs:

详细看官方文档:https://docs.docker.com/compose/compose-file/


image

services:
  web:
    image: hello-world

在 services 标签下的第二级标签是 web,这个名字是用户自己自定义,它就是服务名称。
image 则是指定服务的镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试拉取这个镜像。

例如:

image: redis
image: ubuntu:14.04
image: tutum/influxdb
image: example-registry.com:4000/postgresql
image: a4bc65fd

build

服务除了可以基于指定的镜像,还可以基于一份 Dockerfile,在使用 up 启动之时执行构建任务,这个构建标签就是 build,它可以指定 Dockerfile 所在文件夹的路径。Compose 将会利用它自动构建这个镜像,然后使用这个镜像启动服务容器。

build: /path/to/build/dir

也可以是相对路径,只要上下文确定就可以读取到 Dockerfile。

build: ./dir

设定上下文根目录,然后以该目录为准指定 Dockerfile。

build:
  context: ../
  dockerfile: path/of/Dockerfile

注意 build 都是一个目录,如果你要指定 Dockerfile 文件需要在 build 标签的子级标签中使用 dockerfile 标签指定,如上面的例子。
如果你同时指定了 image 和 build 两个标签,那么 Compose 会构建镜像并且把镜像命名为 image 后面的那个名字。

build: ./dir
image: webapp:tag

既然可以在 docker-compose.yml 中定义构建任务,那么一定少不了 arg 这个标签,就像 Dockerfile 中的 ARG 指令,它可以在构建过程中指定环境变量,但是在构建成功后取消,在 docker-compose.yml 文件中也支持这样的写法:

build:
  context: .
  args:
    buildno: 1
    password: secret

下面这种写法也是支持的,一般来说下面的写法更适合阅读。

build:
  context: .
  args:
    - buildno=1
    - password=secret

与 ENV 不同的是,ARG 是允许空值的。例如:

args:
  - buildno
  - password

这样构建过程可以向它们赋值。

注意:YAML 的布尔值(true, false, yes, no, on, off)必须要使用引号引起来(单引号、双引号均可),否则会当成字符串解析。

command

使用 command 可以覆盖容器启动后默认执行的命令。

command: bundle exec thin -p 3000

也可以写成类似 Dockerfile 中的格式:

command: [bundle, exec, thin, -p, 3000]

container_name

前面说过 Compose 的容器名称格式是:<项目名称><服务名称><序号>
虽然可以自定义项目名称、服务名称,但是如果你想完全控制容器的命名,可以使用这个标签指定:

container_name: app

这样容器的名字就指定为 app 了。

depends_on

在使用 Compose 时,最大的好处就是少打启动命令,但是一般项目容器启动的顺序是有要求的,如果直接从上到下启动容器,必然会因为容器依赖问题而启动失败。
例如在没启动数据库容器的时候启动了应用容器,这时候应用容器会因为找不到数据库而退出,为了避免这种情况我们需要加入一个标签,就是 depends_on,这个标签解决了容器的依赖、启动先后的问题。
例如下面容器会先启动 db 和 redis 两个服务,最后才启动 web 服务:

version: '2'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres

注意的是,默认情况下使用 docker-compose up web 这样的方式启动 web 服务时,也会启动 redis 和 db 两个服务,因为在配置文件中定义了依赖关系。

dns

和 --dns 参数一样用途,格式如下:

dns: 8.8.8.8  

也可以是一个列表:

dns:
  - 8.8.8.8
  - 9.9.9.9

此外 dns_search 的配置也类似:

dns_search: example.com
dns_search:
  - dc1.example.com
  - dc2.example.com

tmpfs

挂载临时目录到容器内部,与 run 的参数一样效果:

tmpfs: /run
tmpfs:
  - /run
  - /tmp

entrypoint

在 Dockerfile 中有一个指令叫做 ENTRYPOINT 指令,用于指定接入点,第四章有对比过与 CMD 的区别。
在 docker-compose.yml 中可以定义接入点,覆盖 Dockerfile 中的定义:

entrypoint: /code/entrypoint.sh

格式和 Docker 类似,不过还可以写成这样:

entrypoint:
    - php
    - -d
    - zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
    - -d
    - memory_limit=-1
    - vendor/bin/phpunit

env_file

还记得前面提到的 .env 文件吧,这个文件可以设置 Compose 的变量。而在 docker-compose.yml 中可以定义一个专门存放变量的文件。
如果通过 docker-compose -f FILE 指定了配置文件,则 env_file 中路径会使用配置文件路径。

如果有变量名称与 environment 指令冲突,则以后者为准。格式如下:

env_file: .env

或者根据 docker-compose.yml 设置多个:

env_file:
  - ./common.env
  - ./apps/web.env
  - /opt/secrets.env

注意的是这里所说的环境变量是对宿主机的 Compose 而言的,如果在配置文件中有 build 操作,这些变量并不会进入构建过程中,如果要在构建中使用变量还是首选前面刚讲的 arg 标签。

environment

与上面的 env_file 标签完全不同,反而和 arg 有几分类似,这个标签的作用是设置镜像变量,它可以保存变量到镜像里面,也就是说启动的容器也会包含这些变量设置,这是与 arg 最大的不同。
一般 arg 标签的变量仅用在构建过程中。而 environment 和 Dockerfile 中的 ENV 指令一样会把变量一直保存在镜像、容器中,类似 docker run -e 的效果。

environment:
  RACK_ENV: development
  SHOW: 'true'
  SESSION_SECRET:

environment:

`
`
* RACK_ENV=development


* SHOW=true



* `SESSION_SECRET
  `

expose

这个标签与Dockerfile中的EXPOSE指令一样,用于指定暴露的端口,但是只是作为一种参考,实际上docker-compose.yml的端口映射还得ports这样的标签。

expose:
 - "3000"
 - "8000"

external_links

在使用Docker过程中,我们会有许多单独使用docker run启动的容器,为了使Compose能够连接这些不在docker-compose.yml中定义的容器,我们需要一个特殊的标签,就是external_links,它可以让Compose项目里面的容器连接到那些项目配置外部的容器(前提是外部容器中必须至少有一个容器是连接到与项目内的服务的同一个网络里面)。

external_links:
 - redis_1
 - project_db_1:mysql
 - project_db_1:postgresql

extra_hosts

添加主机名的标签,就是往/etc/hosts文件中添加一些记录,与Docker client的--add-host类似:

extra_hosts:
 - "somehost:162.242.195.82"
 - "otherhost:50.31.209.229"

启动之后查看容器内部hosts:

162.242.195.82  somehost
50.31.209.229   otherhost

labels

向容器添加元数据,和Dockerfile的LABEL指令一个意思,格式如下:

labels:
  com.example.description: "Accounting webapp"
  com.example.department: "Finance"
  com.example.label-with-empty-value: ""
labels:
  - "com.example.description=Accounting webapp"
  - "com.example.department=Finance"
  - "com.example.label-with-empty-value"

links

还记得上面的depends_on吧,那个标签解决的是启动顺序问题,这个标签解决的是容器连接问题,与Docker client的--link一样效果,会连接到其它服务中的容器。
格式如下:

links:
 - db
 - db:database
 - redis

使用的别名将会自动在服务容器中的/etc/hosts里创建。例如:

172.12.2.186  db
172.12.2.186  database
172.12.2.187  redis

相应的环境变量也将被创建。

logging

这个标签用于配置日志服务。格式如下:

logging:
  driver: syslog
  options:
    syslog-address: "tcp://192.168.0.42:123"

默认的driver是json-file。只有json-file和journald可以通过docker-compose logs显示日志,其他方式有其他日志查看方式,但目前Compose不支持。对于可选值可以使用options指定。
有关更多这方面的信息可以阅读官方文档:
https://docs.docker.com/engine/admin/logging/overview/

pid

将PID模式设置为主机PID模式,跟主机系统共享进程命名空间。容器使用这个标签将能够访问和操纵其他容器和宿主机的名称空间。

pid: "host"

ports

映射端口的标签。
使用HOST:CONTAINER格式或者只是指定容器的端口,宿主机会随机映射端口。

ports:
 - "3000"
 - "8000:8000"
 - "49100:22"
 - "127.0.0.1:8001:8001"

注意:当使用HOST:CONTAINER格式来映射端口时,如果你使用的容器端口小于60你可能会得到错误得结果,因为YAML将会解析xx:yy这种数字格式为60进制。所以建议采用字符串格式。

security_opt

为每个容器覆盖默认的标签。简单说来就是管理全部服务的标签。比如设置全部服务的user标签值为USER。

security_opt:
  - label:user:USER
  - label:role:ROLE

stop_signal

设置另一个信号来停止容器。在默认情况下使用的是SIGTERM停止容器。设置另一个信号可以使用stop_signal标签。

stop_signal: SIGUSR1

volumes

挂载一个目录或者一个已存在的数据卷容器,可以直接使用 [HOST:CONTAINER] 这样的格式,或者使用 [HOST:CONTAINER:ro] 这样的格式,后者对于容器来说,数据卷是只读的,这样可以有效保护宿主机的文件系统。
Compose的数据卷指定路径可以是相对路径,使用 . 或者 ... 来指定相对目录。
数据卷的格式可以是下面多种形式:

volumes:
  // 只是指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)。
  - /var/lib/mysql

// 使用绝对路径挂载数据卷




* /opt/data:/var/lib/mysql




// 以 Compose 配置文件为中心的相对路径作为数据卷挂载到容器。




* ./cache:/tmp/cache




// 使用用户的相对路径(\~/ 表示的目录是 /home/\<用户目录\>/ 或者 /root/)。




* ~/configs:/etc/configs/:ro




// 已经存在的命名的数据卷。

`
`
* `datavolume:/var/lib/mysql
  `

如果你不使用宿主机的路径,你可以指定一个volume_driver。

volume_driver: mydriver

volumes_from

从其它容器或者服务挂载数据卷,可选的参数是 :ro或者 :rw,前者表示容器只读,后者表示容器对数据卷是可读可写的。默认情况下是可读可写的。

volumes_from:
  - service_name
  - service_name:ro
  - container:container_name
  - container:container_name:rw

cap_add, cap_drop

添加或删除容器的内核功能。

cap_add:
  - ALL

cap_drop:

`
`
* NET_ADMIN


* `SYS_ADMIN
  `

cgroup_parent

指定一个容器的父级cgroup。

cgroup_parent: m-executor-abcd

devices

设备映射列表。与Docker client的--device参数类似。

devices:
  - "/dev/ttyUSB0:/dev/ttyUSB0"

extends

这个标签可以扩展另一个服务,扩展内容可以是来自在当前文件,也可以是来自其他文件,相同服务的情况下,后来者会有选择地覆盖原有配置。

extends:
  file: common.yml
  service: webapp

用户可以在任何地方使用这个标签,只要标签内容包含file和service两个值就可以了。file的值可以是相对或者绝对路径,如果不指定file的值,那么Compose会读取当前YML文件的信息。

network_mode

网络模式,与Docker client的--net参数类似,只是相对多了一个service:[service name] 的格式。
例如:

network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"

可以指定使用服务或者容器的网络。

networks

加入指定网络,格式如下:

services:
  some-service:
    networks:
     - some-network
     - other-network

关于这个标签还有一个特别的子标签aliases,这是一个用来设置服务别名的标签,例如:

services:
  some-service:
    networks:
      some-network:
        aliases:
         - alias1
         - alias3
      other-network:
        aliases:
         - alias2

相同的服务可以在不同的网络有不同的别名。

其他

还有这些标签:cpu_shares, cpu_quota, cpuset, domainname, hostname, ipc, mac_address, mem_limit, memswap_limit, privileged, read_only, restart, shm_size, stdin_open, tty, user, working_dir

上面这些都是一个单值的标签,类似于使用docker run的效果。

cpu_shares: 73
cpu_quota: 50000
cpuset: 0,1

user: postgresql
working_dir: /code


domainname: foo.com
hostname: foo
ipc: host
mac_address: 02:42:ac:11:65:43


mem_limit: 1000000000
memswap_limit: 2000000000
privileged: true


restart: always

`read_only: true
shm_size: 64M
stdin_open: true
tty: true
`


一键搭建博客 {#%E4%B8%80%E9%94%AE%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2}

地址:https://docs.docker.com/compose/wordpress/

下载程序、安装数据库、配置......

compose应用. => 一键启动

1、下载项目(docker-compose.yaml)

2、如果需要文件。Dcokerfile

3、文件准备齐全(直接一键启动项目!)

一切都很简单!

总结:

工程、服务、容器

项目compose:三层

  • 工程 Project
  • 服务 服务
  • 容器 运行实例!

Docker Swarm {#docker-swarm}

暂无

@@ {#%40%40}

赞(1)
未经允许不得转载:工具盒子 » Docker总结(命令、镜像、容器、数据卷、DockerFile、网络、Compose)