Docker

目录

1、简介
2、安装
3、常用命令
4、数据管理
5、Dockerfile
6、网络连接
7、仓库管理
8、图形界面
9、镜像原理
10、Compose
11、Swarm
12、拓展

1、简介

什么是Docker?

Docker 是基于Go语言开发的一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。


为什么要使用Docker?

对于开发和运维人员来说,最希望的效果就是一次创建或者配置后,可以在任意地方、任意时间让应用正常运行,对于算法研究人员来说,可能不同的算法需要不同版本的软件,那么在同一个环境中就会存在冲突,docker 的环境隔离就可以很方便的用于不同环境的配置。具体来说,docker优势主要有以下几个方面:

  • 快速交付和部署

    使用docker,开发人员可以使用镜像快速构建一套标准的开发环境;开发完成后,测试和运维人员可以使用完全相同的环境部署代码,只要是开发测试过的代码就可以确保在生产环境无缝运行。docker可以快速创建和删除容器,实现快速迭代。

  • 高效的资源利用

    运行docker容器不需要额外的虚拟化管理程序的支持,docker是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。

  • 轻松的迁移和扩展

    docker容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、服务器等,同时支持主流的操作系统发行版本,这种兼容性让用户可以在不同平台间轻松的迁移应用。

  • 简单的更新管理

    使用Dockerfile生成镜像的方式,只需要小小的配置修改,就可以替代以往大量的更新工作,所有的修改都以增量的方式进行分发和更新,从而实现自动化且高效的容器管理。


Docker为什么比VM快?

  • Docker有着比虚拟机更少的抽象层
  • docker利用的是宿主机的内核,vm需要Guest OS。
  • 所以说新建一个容器的时候,docker不需要向虚拟机一样重新加载一个操作系统,直接利用宿主机的内核。虚拟机是加载Guest OS。

历史

2010年几个年轻人成立了一个做PAAS平台的公司dotCloud。起初公司发展的不错,不但拿到过一些融资,还获得了美国著名孵化器YCombinator的支持,后来微软谷歌亚马逊这样的大厂商也纷纷加入PAAS平台,竞争十分激烈,dotCloud举步维艰。

2013年可能是公司发展的不是很好,工程师又不想自己的努力付之东流,于是他们决定将他们的核心技术开源。这项技术就是docker。当时docker的功能就是将linux容器中的应用代码打包,可以轻松的在服务器之间进行迁移。

无心插柳柳成荫,docker技术风靡全球,于是dotCloud公司改名为docker Inc,并全面投入到docker的开发之中。

2014年 Docker 发布1.0版本,2015年Docker 提供 Docker-machine,支持 windows 平台。

在此期间,Docker 项目在开源社区大受追捧,同时也被业界诟病的是 Docker 公司对于 Docker 发展具有绝对的话语权,比如 Docker 公司推行了 libcontainer 难以被社区接受。

为了防止 Docker 这项开源技术被Docker 公司控制,在几个核心贡献的厂商,诸如 Redhat,谷歌的倡导下,成立了 OCI 开源社区。

OCI 开源社区旨在于将 Docker 的发展权利回归社区,当然反过来讲,Docker 公司也希望更多的厂商安心贡献代码到Docker 项目,促进 Docker 项目的发展。

于是通过OCI建立了 runc 项目,替代 libcontainer,这为开发者提供了除 Docker 之外的容器化实现的选择。

OCI 社区提供了 runc 的维护,而 runc 是基于 OCI 规范的运行容器的工具。换句话说,你可以通过 runc,提供自己的容器实现,而不需要依赖 Docker。当然,Docker 的发行版底层也是用的 runc。在 Docker 宿主机上执行 runc,你会发现它的大多数命令和 Docker 命令类似,感兴趣的读者可以自己实践如何用 runc 启动容器。

至2017年,Docker 项目转移到 Moby 项目,基于 Moby 项目,Docker 提供了两种发行版,Docker CE 和 Docker EE, Docker CE 就是目前大家普遍使用的版本,Docker EE 成为付费版本,提供了容器的编排,Service 等概念。Docker 公司承诺 Docker 的发行版会基于 Moby 项目。这样一来,通过 Moby 项目,你也可以自己打造一个定制化的容器引擎,而不会被 Docker 公司绑定。


思想

Docker的主要思想就是集装箱思想,就是说当我们把项目从一个地方搬到另一个地方,难免会丢失某些配置或数据导致项目无法运行,而有个集装箱,就可以把项目的所有东西都丢到集装箱里面,这样自然不会出现项目移植到另一个环境就跑不起来的情况。

Docker还简化了部署过程,Docker运输东西有一个超级码头(仓库),任何地方需要货物都由鲸鱼先送到超级码头,然后再由鲸鱼从超级码头把货物送到目的地去。比如把A电脑的项目搬到B电脑上,那么直接执行一条命令让鲸鱼将货物搬过来即可。

同时,由于Docker是一个集装箱,那么我们自然可以设定它的大小,这样就不会因为死循环疯狂吃内存,导致全部崩盘,最多只是集装箱出问题罢了。


概念

镜像(image):镜像就好比一个模板,可以通过这个模板创建多个容器,通过镜像可以创建多个容器。

容器(container):Docker利用容器技术独立运行一个或者一个组应用,可以把容器理解成一个简陋版的Liunx系统。

仓库(repository):仓库就是存放镜像的地方,分为公有仓库和私有仓库,类似于maven的中央仓库和私服。


运行流程

Docker_第1张图片


官网:https://www.docker.com/
官方文档:https://docs.docker.com/get-started/
Docker Hub: https://hub.docker.com/


2、安装

Linux

准备工作
# Linux服务器一台,且上面的安装的Centos系统内核要不低于3.10。你可以通过 uname -r 来查询当前内核版本。
uname -r

# 清除系统残余项
sudo yum remove docker \
      docker-client \
      docker-client-latest \
      docker-common \
      docker-latest \
      docker-latest-logrotate \
      docker-logrotate \
      docker-selinux \
      docker-engine-selinux \
      docker-engine

#安装下载Docker依赖的工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2

#添加阿里云的软件源
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

#更新yum缓存(为了保证能更新和下载需要的服务:如docker)
sudo yum makecache fast
开始安装
#安装Docker(Docker版本分为CE(社区免费版)和EE(企业版,安全CE)
sudo yum -y install docker-ce

#启动Docker
sudo systemctl start docker

#查看Docker是否成功
docker info
sudo docker run hello-world
补充
#设置开机自启
systemctl enable docker

#移除Docker-ce服务
yum remove docker-ce

#删除Docker依赖项
rm -rf /var/lib/docke

3、常用命令

帮助命令

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

镜像命令

查看镜像
docker images

请添加图片描述

各个选项说明:

  • **REPOSITORY:**表示镜像的仓库源
  • **TAG:**镜像的标签,也可以说是版本号
  • **IMAGE ID:**镜像ID
  • **CREATED:**镜像创建时间
  • **SIZE:**镜像大小
#可选项,可组合使用
-a, --all             # 列出全部镜像

-q, --quiet           # 只列出镜像id

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KpdwPXAz-1655120249155)(docs/imgs/1654601224442.png)]


搜索镜像

我们可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为: https://hub.docker.com/

Docker_第2张图片

也可以使用docker search命令来搜索镜像

docker search 镜像名

#可选项
-f, --filter 	#通过搜索来过滤

Docker_第3张图片

[root@VM-12-10-centos ~]# docker search mysql -f=STARS=3000		#搜索STARS大于3000的
NAME      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql     MySQL is a widely used, open-source relation…   12693     [OK]       
mariadb   MariaDB Server is a high performing open sou…   4871      [OK]

各个选项说明:

  • NAME: 镜像仓库源的名称
  • DESCRIPTION: 镜像的描述
  • OFFICIAL: 是否 docker 官方发布
  • stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。
  • AUTOMATED: 自动构建。

拖取镜像
docker pull 镜像名

Docker_第4张图片

Docker_第5张图片


删除镜像
docker rmi -f 镜像的id或者名称				#删除一个镜像
docker rmi -f $(docker images -aq)		 #删除全部镜像

Docker_第6张图片

创建镜像

当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,可以通过以下两种方式对镜像进行更改。

  • 从已经创建的容器中更新镜像,并且提交这个镜像
  • 使用 Dockerfile 指令来创建一个新的镜像

这里进行第一种方式的讲解,关于Dockerfile创建镜像,将在以后的章节进行讲解。

#这里先这样写,下一节将会讲解容器的相关知识

[root@VM-12-10-centos ~]# docker run -itd --name tomcat01 tomcat	#创建容器
f57398ba1d274a542ac518f58d35b363b21827a1c9d9f9c4ec02abfc78ee80fa
[root@VM-12-10-centos ~]# docker ps									#查看运行中的容器
CONTAINER ID   IMAGE     COMMAND             CREATED          STATUS          PORTS      NAMES
f57398ba1d27   tomcat    "catalina.sh run"   22 seconds ago   Up 21 seconds   8080/tcp   tomcat01
[root@VM-12-10-centos ~]# docker exec -it f57398ba1d27 /bin/bash	#进入容器内部
root@f57398ba1d27:/usr/local/tomcat# 


# 由于是精简版的tomcat,很多命令是无法执行的,这里安装一些东西,将tomcat改造成我们需要的tomcat

# 执行更新命令:
apt-get update -y

# 执行下载 iproute2 命令:
apt install -y iproute2

#执行下载 iputils-ping 命令,让ping命令生效:
apt install iputils-ping

#下载完毕后,退出容器
Ctrl+P+Q

#进行提交
docker commit -m="hello.java" -a="thl" f57398ba1d27 tomcat:v1

各个参数说明:

  • -m: 提交的描述信息
  • -a: 指定镜像作者
  • **f57398ba1d27:**容器 ID
  • tomcat:v1 指定要创建的目标镜像名

查看镜像

[root@VM-12-10-centos ~]# docker images
REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
tomcat            v1        747d384aa76e   24 hours ago   705MB
tomcat            latest    c795915cb678   13 days ago    680MB

测试

#首先查看使用精简版tomcat创建的容器
[root@VM-12-10-centos ~]# docker run -itd --name simpletomcat tomcat	#创建容器
daef93c8f774487a6134083a0bd748f0e6354cd4ecf039a0c2c37cca0c069d20
[root@VM-12-10-centos ~]# docker exec -it simpletomcat ip addr			#查看该容器的ip
OCI runtime exec failed: exec failed: unable to start container process: exec: "ip": executable file not found in $PATH: unknown

#精简版是不支持命令的,接下来用我们自己的镜像来创建容器
[root@VM-12-10-centos ~]# docker run -itd --name mytomcat tomcat:v1		#创建容器
daef93c8f774487a6134083a0bd748f0e6354cd4ecf039a0c2c37cca0c069d20
[root@VM-12-10-centos ~]# docker exec -it mytomcat ip addr				#查看该容器的ip
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
50: eth0@if51: <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

设置标签
docker tag <容器 ID> 用户名称、镜像源名:新的标签名

Docker_第7张图片


容器命令

新建容器并运行

新建容器之前,必须要有镜像,如果没有镜像,直接创建容器,那么docker会自动帮我们到远程仓库拉取镜像,如果远程仓库没有就会报错。

docker run [可选参数] image 命令

#可选参数
--name="Name" 					#容器名称 如mysql1,mysql2,用来区分容器
-d								#后台方式运行
-t								#在新容器内指定一个伪终端或终端。
-i								#允许你对容器内的标准输入 (STDIN) 进行交互。
-p								#指定容器的端口 -p 8080:8080
	-p ip:主机端口:容器端口
	-p 主机端口:容器端口(常用)
	-p 容器端口
-P 								#随机指定端口
-v								#指定卷的路径
	--volumes-from list   		#从指定容器装载卷

测试

[root@VM-12-10-centos ~]# docker images						#查看镜像,这里只有mysql的镜像
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
mysql        5.7       2a0961b7de03   10 days ago   462MB
[root@VM-12-10-centos ~]# docker run -it centos /bin/bash	#运行并进入centos容器
Unable to find image 'centos:latest' locally				#没有centos镜像
latest: Pulling from library/centos							#这里在自动拉取
a1d0c7532777: Pull complete 
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
[root@d176336c8383 /]# ls									#这里已经进入了容器,ls列出查看目录
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@d176336c8383 /]# exit									#退出容器
exit
[root@VM-12-10-centos ~]# cd /								#已经回到主机,切换到根目录
[root@VM-12-10-centos /]# ls								#查看主机的目录,发现与容器内部有些不同
bin  boot  data  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@VM-12-10-centos /]# docker images						#查看镜像,多了一个centos镜像
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
mysql        5.7       2a0961b7de03   10 days ago    462MB
centos       latest    5d0da3dc9764   8 months ago   231MB
列出容器
#列出正在运行的容器
docker ps [可选参数]		

#可选参数
-a				#列出当前正在运行的容器和历史运行过的容器
-n=?			#显示最近创建的容器,问号代表的是需要显示的条数,如 -n=1 -n=2等
-q				#只显示容器的编号

Docker_第8张图片

输出详情介绍:

  • CONTAINER ID: 容器 ID。

  • IMAGE: 使用的镜像。

  • COMMAND: 启动容器时运行的命令。

  • CREATED: 容器的创建时间。

  • STATUS: 容器状态。

  • 状态有7种:

    1、created(已创建)

    2、restarting(重启中)

    3、running 或 Up(运行中)

    4、removing(迁移中)

    5、paused(暂停)

    6、exited(停止)

    7、dead(死亡)

  • PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。

  • NAMES: 自动分配的容器名称。

退出容器
exit			#退出容器且停止运行
Ctrl+D			#退出容器且停止运行
Ctrl+P+Q		#退出容器不停止运行

删除容器
docker rm -f <容器 ID>			#强制删除一个容器,如果不加 -f,则正在运行的容器无法删除
docker rm -f $(docker ps -aq)	 #删除全部容器
docker ps -a -q|xargs docker rm  #删除全部容器
docker container prune			 #清理掉所有处于终止状态的容器

Docker_第9张图片

启动容器
docker start <容器 ID>		#启动容器
docker restart <容器 ID>		#重启容器

停止容器
docker stop <容器 ID>			#停止正在运行的容器
docker kill <容器 ID>			#强制停止当前容器

后台运行

在大部分的场景下,我们希望 docker 的服务是在后台运行的,可以过 -d 指定容器的运行模式

docker run -itd --name centos-test centos /bin/bash

**注:**加了 -d 参数默认不会进入容器,想要进入容器需要使用指令 docker exec(下面会介绍到)。


进入容器

在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:

#输入exit命令从容器退出,会导致容器的停止,但是Ctrl+P+Q不会,不过attach有些问题,有可能无法进入到容器内部
docker attach <容器 ID>

#输入exit命令从容器退出,不会导致容器的停止,更推荐使用
docker exec -it <容器 ID> /bin/bash

文件复制
#将docker内的文件拷贝到主机上
docker cp <容器 ID>:容器内文件路径 主机路径

导出容器

如果要导出本地某个容器,可以使用 docker export 命令。

docker export <容器 ID> > 文件

测试

#导出容器 daef93c8f774 快照到本地文件 tomcat.tar
[root@VM-12-10-centos ~]# docker export daef93c8f774 > tomcat.tar
[root@VM-12-10-centos ~]# ls
tomcat.tar

导入容器

可以使用 docker import 从容器快照文件中再导入为镜像

docker import 快照文件路径 Repository:tag

测试

[root@VM-12-10-centos ~]# docker import tomcat.tar tomcat:v1.2
sha256:e9540b2102f62605925dc1ef7769a281277987c354c3f47a40c374f38ae71751
[root@VM-12-10-centos ~]# docker images
REPOSITORY        TAG       IMAGE ID       CREATED         SIZE
tomcat            v1.2      e9540b2102f6   8 seconds ago   694MB
tomcat            v1        747d384aa76e   25 hours ago    705MB
tomcat            v1.1      747d384aa76e   25 hours ago    705MB

此外,也可以通过指定 URL 或者某个目录来导入,例如:

docker import http://example.com/exampleimage.tgz example/imagerepo

容器信息
#查看容器的进程信息
docker top <容器 ID>

#查看容器的元数据
docker inspect <容器 ID>

查看日志
docker logs	[可选参数] <容器 ID>

#可选参数
-f			#日志格式
-t			#显示时间戳
--tail		#要显示的条数

测试

#示例,创建一个容器,并编写一段shell脚本,打印信息
docker run -itd centos /bin/sh -c "while true;do echo thl;sleep 1;done"
#查看
docker logs -ft aa460ba02cd0
docker logs -ft --tail=10 aa460ba02cd0

4、数据管理

在生产环境中使用 Docker ,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作,容器中的数据管理主要有两种方式:

  • 数据卷:Data Volumes 容器内数据直接映射到本地主机环境
  • 数据卷容器(Data Volume Containers):使用特定容器维护数据卷

数据卷

数据卷是一个可供一个或多个容器使用的特殊目录,它将主机操作系统目录直接映射进容器,它可以提供很多有用的特性:

  1. 数据卷可以在容器之间共享和重用
  2. 对数据卷的修改会立马生效
  3. 对数据卷的更新,不会影响镜像
  4. 数据卷默认会一直存在,即使容器被删除

语法
docker run -it -v 主机目录:容器内目录 镜像 命令

-v 宿主机路径:容器内路径    #指定路径挂载
-v 容器内路径   			 #匿名挂载
-v 卷名:容器内路径   		#具名挂载

#拓展:
宿主机路径:容器内路径 : ro          #只读
宿主机路径:容器内路径 : rw      	#可读可写
#如果是ro说明这个路径只能通过宿主机来操作,容器内部无法操作!

指定路径挂载
#数据卷
docker run -it --name="centos01" -v /home/test:/home centos /bin/bash

#查看容器信息
docker inspect centos01

Docker_第10张图片

在容器中的home目录创建hello.java,在主机的home/test文件夹中会出现hello.java,反之亦然。


匿名挂载
[root@VM-12-10-centos ~]# docker volume ls									#查看挂载的卷
DRIVER    VOLUME NAME
[root@VM-12-10-centos ~]# docker run -d -P -v /etc/nginx nginx				#匿名挂载
c95a97b3f6f133b18365ea0a0791782b931c087aae3a42d1a7aadd8dd7bdffc1
[root@VM-12-10-centos ~]# docker volume ls									#再次查看挂载的卷
DRIVER    VOLUME NAME
local     5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e	#卷名称是匿名的,不易分辨
[root@VM-12-10-centos ~]# docker inspect 5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e
[
    {
        "CreatedAt": "2022-06-08T18:45:21+08:00",
        "Driver": "local",
        "Labels": null,
        #宿主机映射的数据卷路径
        "Mountpoint": "/var/lib/docker/volumes/5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e/_data",
        "Name": "5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e",
        "Options": null,
        "Scope": "local"
    }
]


具名挂载
[root@VM-12-10-centos ~]# docker run -d -P -v juming-nginx:/etc/nginx nginx	#具名挂载
81f727086d846ba719a564ae1e934fbfbd68dcdf5dd49036a855560d63b354e1
[root@VM-12-10-centos ~]# docker volume ls									#查看卷
DRIVER    VOLUME NAME
local     5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e
local     juming-nginx														#这里是有名字的,更方便分辨卷
[root@VM-12-10-centos ~]# docker volume inspect juming-nginx				#查看信息
[
    {
        "CreatedAt": "2022-06-08T18:49:19+08:00",
        "Driver": "local",
        "Labels": null,
        #宿主机映射的数据卷路径
        "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]


权限
docker run -d -P -v nginx01:/etc/nginx:ro nginx		#只读
docker run -d -P -v nginx02:/etc/nginx:rw nginx		#可读可写

小结
  • docker 容器中所有的卷,在没有指定目录的情况下,都在==var/lib/docker/volumes/==下。
  • 具名和匿名挂载的方式,可以让我们的卷统一的放在一个地方,方便我们查找。
  • 大多数情况下,使用具名挂载。

数据卷容器

如果需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门提供数据卷给其他容器挂载。

#创建一个数据卷容器,这种挂载的方式是匿名挂载
docker run -itd --name="t1" -v /docker01 centos

#与数据卷容器绑定
docker run -itd --name t2 --volumes-from t1 centos

#由于t2和t1绑定了,所以t3和t2绑定也可以将数据卷挂载上去
docker run -itd --name t3 --volumes-from t2 centos

Docker_第11张图片


小结

其实数据卷容器就是容器绑定数据卷的一种方式,比如我们创建t1容器,然后创建t2容器,数据卷挂载的路径指定t1挂载的路径,这样t1和t2就绑定了同一个数据卷,它们之间就能实现数据共享。而数据卷容器就是让我们在创建t2容器的时候,不必指定t1数据卷的挂载路径,而是直接指定t1容器就可以了,这避免了我们在指定路径时可能会写错路径的情况。


5、Dockerfile

前面提到过构建镜像的方式有两种,一种是从已经创建的容器中更新镜像,并且提交这个镜像,另一种就是Dockerfile了。Dockerfile是用来构建docker镜像的文件,是命令脚本,通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个一个的命令,每个命令都是一层。


指令

每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的,执行从上到下顺序执行,#表示注释。

指令 作用
FROM 指定基础镜像
MAINTAINER 指定镜像的维护者信息,一般为名字+邮箱
RUN 镜像构建时需要执行的命令
ADD 增加文件,会自动解压
WORKDIR 设置当前工作目录
VOLUME 挂载主机目录
EXPOSE 暴露端口,注意这里指仅暴露容器的端口,并不会将容器端口与宿主机端口映射。也就是说在使用docker run的时候仍然需要继续使用-p进行端口映射,换言之,EXPOSE更多的作用在于给Dockerfile开发者提供开发端口的提示提示作用
CMD 指定容器启动的时候需要执行的命令,注意CMD只有最后一个命令会生效,可被替换
ENTRYPOINT 指定容器启动时需要运行的命令,注意ENTRYPOINT命令可以追加命令,在docker run时,追加命令会生效
ONBUILD 当构建一个被继承Dockerfile,这个时候就会运行ONBUILD指令
COPY 类似ADD命令,将文件拷贝到镜像中
ENV 构建的时候设置环境变量

构建镜像

dockerfile
FROM centos								

MAINTAINER thl			

ENV JAVA_HOME /usr/local/jdk_1.8/		

WORKDIR /usr/local						

RUN yum install -y vim					
RUN yum install -y net-tools			

EXPOSE 80								

CMD echo $JAVA_HOME						
CMD echo "---end---"
CMD /bin/bash
构建镜像
docker build -f dockerfile -t mycentos:1.0 .

参数说明:

  • -f:指定dockerfile文件
  • -t :指定要创建的目标镜像名以及tag
  • . :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径

如果失败了,将dockerfile第一行改为:FROM centos:7即可。因为Centos8不再维护,2022年1月31日,Centos团队从官方镜像中移除了CentOS8的所有包。

测试
[root@VM-12-10-centos ~]# docker images
REPOSITORY        TAG       IMAGE ID       CREATED         SIZE
mycentos          1.0       95f3a2a6b615   2 minutes ago   601MB
[root@VM-12-10-centos ~]# docker run -it mycentos:1.0				#可以发现这里运行时没有追加 /bin/bash
[root@f409fdad662f local]# pwd
/usr/local

进入容器后,输入pwd会发现目录是==/usr/local==,输入clear发现能够清屏了。


查看镜像的构建历史

语法

docker history	镜像名或镜像ID

测试

[root@VM-12-10-centos ~]# docker history mycentos:1.0
IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
95f3a2a6b615   6 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B        
dd3bc424a7ce   6 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
bf2e41afb395   6 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
2e8082a693b5   6 minutes ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
75d2a8078746   6 minutes ago   /bin/sh -c yum install -y net-tools             171MB     
bfd024d04b70   6 minutes ago   /bin/sh -c yum install -y vim                   226MB     
cf1a5b2b0118   8 minutes ago   /bin/sh -c #(nop) WORKDIR /usr/local            0B        
c53da378573d   8 minutes ago   /bin/sh -c #(nop)  ENV JAVA_HOME=/usr/local/…   0B        
fd3d5b1df6d9   8 minutes ago   /bin/sh -c #(nop)  MAINTAINER thl
eeb6ee3f44bd   9 months ago    /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      9 months ago    /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B        
<missing>      9 months ago    /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB  

可以看到指令是一条一条执行的


CMD和ENTRYPOINT对比

#CMD
#dockerfile-cmd
FROM centos
CMD ["ls","-a"]

#编译
docker build -f dockerfile-cmd -t cmd .

#在后方追加-l,会报错
[root@VM-12-10-centos home]# docker run f3c1c8b34c72 -l
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled 
#ENTRYPOINT
#dockerfile-entrypoint

#编译
docker build -f entry -t enrty .

#在后方追加-l,正确显示
[root@VM-12-10-centos home]# docker run a3cc724a748e -l
total 56
drwxr-xr-x   1 root root 4096 Jun  9 06:41 .
drwxr-xr-x   1 root root 4096 Jun  9 06:41 ..
-rwxr-xr-x   1 root root    0 Jun  9 06:41 .dockerenv
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root  340 Jun  9 06:41 dev
drwxr-xr-x   1 root root 4096 Jun  9 06:41 etc
drwxr-xr-x   2 root root 4096 Nov  3  2020 home
lrwxrwxrwx   1 root root    7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root 4096 Sep 15  2021 lost+found
drwxr-xr-x   2 root root 4096 Nov  3  2020 media
drwxr-xr-x   2 root root 4096 Nov  3  2020 mnt
drwxr-xr-x   2 root root 4096 Nov  3  2020 opt
dr-xr-xr-x 133 root root    0 Jun  9 06:41 proc
dr-xr-x---   2 root root 4096 Sep 15  2021 root
drwxr-xr-x  11 root root 4096 Sep 15  2021 run
lrwxrwxrwx   1 root root    8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Nov  3  2020 srv
dr-xr-xr-x  13 root root    0 Jun  8 11:52 sys
drwxrwxrwt   7 root root 4096 Sep 15  2021 tmp
drwxr-xr-x  12 root root 4096 Sep 15  2021 usr
drwxr-xr-x  20 root root 4096 Sep 15  2021 var

数据卷

使用Dockerfile构建镜像时,也可以挂载数据卷。

FROM centos

VOLUME ["volume01","volume02"]

CMD echo "===end==="
CMD /bin/bash

构建镜像

docker build -f dockerfile -t thl-centos:1.0 .

Docker_第12张图片

使用镜像创建一个容器,不挂载数据卷,然后查看目录。

Docker_第13张图片

这个卷是匿名挂载,与主机有一个关联的目录

Docker_第14张图片


总结

使用dockerfile创建镜像的时候,可以设定挂载卷,但是这个卷是匿名的,通常情况下是在创建容器的时候挂载卷,因为这样更加灵活。


6、网络连接

到目前为止,我们的所有Docker容器都是公开端口并绑定到本地网络接口的,这样可以把容器里的服务在本地Docker宿主机所在的外部网络上(比如 docker run -p 81:80 nginx, 就是把容器里的80端口公开给宿主机的81端口)公开。除了这种用法外,还有一种就是内部网络。


docker0

在安装Docker时,会在宿主机上创建一个新的网络接口,名字是docker0,网络接口docker0是一个虚拟的以太网桥,它专门用于连接容器和本地宿主机网络,每个Docker容器都会在这个接口上分配一个IP地址,接口本身的地址是172.17.0.1,子网掩码是255.255.0.0,也就是说Docker会默认使用172.17.X.X作为子网地址。

#运行一个容器
docker run -d -P --name tomcat01 tomcat

#由于是精简版的tomcat,很多命令是无法执行的,需要安装一些东西
# 执行一下更新命令:
apt-get update -y
# 执行下载 iproute2命令:
apt install -y iproute2
#执行下载 iputils-ping命令,让ping命令生效:
apt install iputils-ping

#下载完需要的东西之后,可以将其提交为镜像,之后创建的容器就可以使用自己改造过后的镜像创建tomcat容器了

#查看容器 ip addr
[root@VM-12-10-centos ~]# docker exec -it tomcat01 ip addr
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
8: eth0@if9: <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

#看看是否能ping通容器
[root@VM-12-10-centos ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.036 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.050 ms

#按照上面的步骤再创建一个容器tomcat02,然后尝试能否ping通tomcat01
docker exec -it tomcat02 ping 172.17.0.2

原理
  1. 每启动一个容器,docker就会给容器分配一个ip,只要安装了docker,就会有一个网卡docker0。
  2. 容器和容器之间是可以互相ping通的,tomcat01和tomcat02并不是直接连接的,而是共用的一个路由器,docker0,所有容器不指定容器的情况下,都是docker0路由,docker会给容器分配一个默认可用的ip
  3. docker0是桥接模式,使用的技术是evth-pair技术!
  4. docker中所有的网络接口都是虚拟的,虚拟的转发效率高
  5. 只要容器删除,对应网桥一对就没了
  6. docker0不支持容器名连接访问,自定义网络才是主流

–link

--link是一项比较古老的技术,在实际中不建议使用

[root@VM-12-10-centos ~]# docker run -d --name="tomcat03" -P --link tomcat01 tomcat:v2
ef4d2ecf0ae9e64ae41048032cb32f8e0806eb16d968bca5a8e1ff79c69f48cc
[root@VM-12-10-centos ~]# docker exec -it tomcat03 ping tomcat01	#直接ping容器名就可以ping通
PING tomcat01 (172.17.0.2) 56(84) bytes of data.
64 bytes from tomcat01 (172.17.0.2): icmp_seq=1 ttl=64 time=0.101 ms
  • 反过来tomcat01去ping tomcat03就不行了,因为没有配置
  • –link就是在hosts配置中增加了一个映射

自定义网络

#查看docker网络
docker network ls

#测试
[root@VM-12-10-centos ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
253c657ee003   bridge    bridge    local
7383cb2c4079   host      host      local
b5e4aa2a23b3   none      null      local

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

#自定义网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

测试

#创建两个容器,指定我们自定义的网络
[root@VM-12-10-centos ~]# docker run -d -P --name tomcat-mynet-01 --net mynet tomcat:v2
f6d15950a157f0824eed450a45e58a26204b52b307691176a0500f47705c5f21
[root@VM-12-10-centos ~]# docker run -d -P --name tomcat-mynet-02 --net mynet tomcat:v2
8c22d4633a19d478a5073eb4c3b6d1b5827e83b3768095f03638e95ceae56b09

#使用ip地址去ping,可以ping通
[root@VM-12-10-centos ~]# docker exec -it tomcat-mynet-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.078 ms

#使用容器名去ping,也可以ping通
[root@VM-12-10-centos ~]# docker exec -it tomcat-mynet-01 ping tomcat-mynet-02
PING tomcat-mynet-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-mynet-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.049 ms

结论

  • 自定义的网络修复了docker0的缺陷
  • 推荐使用自定义网络
  • 自定义网络可以保证集群的安全和健康

网络联通

把一个容器连接到一个网络上

#测试打通tomcat01和mynet
docker network connect mynet tomcat01 

#连通之后就是将tomcat01放到了mynet网络下
#官网:一个容器两个ip

#测试
[root@VM-12-10-centos ~]# docker exec -it tomcat01 ping tomcat-mynet-01
PING tomcat-mynet-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-mynet-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.084 ms

#tomcat01是docker0网卡下的,但是可以连通tomcat-mynet-01,就是因为tomcat01打通了mynet
#但是与tomcat01相连的tomcat02却无法连通tomcat-mynet-01,因为它没有打通mynet
[root@VM-12-10-centos ~]# docker exec -it tomcat02 ping tomcat-mynet-01
ping: tomcat-mynet-01: Name or service not known

网络端口映射

容器互联

端口映射并不是唯一把 docker 连接到另一个容器的方法。

docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。

docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。


7、仓库管理

仓库(Repository)是集中存放镜像的地方。目前 Docker 官方维护了一个公共仓库 Docker Hub。大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。当然不止 docker hub,国内如阿里云,腾讯云也有镜像仓库。


Docker Hub

注册

在 https://hub.docker.com 免费注册一个 Docker 账号。

登录退出
#登录
docker login

#退出
docker logout
发布镜像

用户登录后,通过docker push命令将镜像推送到 Docker Hub。以下命令中的 username 请替换为你的 Docker 账号用户名。

#修改镜像的tag,这一步至关重要的,原因和Git push代码一样,为了安全起见,在Docker Hub无法确定操作者的情况下,是无法完成push操作的。将tag改为用户名开头,则可以避免出现denied: requested access to the resource is denied异常
docker tag mycentos:0.1 username/mycentos:0.1

#发布到Docker Hub中
docker push username/mycentos:0.1

Docker_第15张图片


腾讯云

使用腾讯的容器服务,其实与Docker Hub是一样的。首先找到容器服务。

Docker_第16张图片

如果是第一次,这里会让我们授予权限,同意即可

Docker_第17张图片

授权之后,找到镜像仓库

Docker_第18张图片

开启服务

Docker_第19张图片

继续授权

Docker_第20张图片

新建一个实例

Docker_第21张图片

这里进行测试,所以使用免费的。

Docker_第22张图片

会让注册一个容器账号,类似于Docker Hub账号

Docker_第23张图片

要新建命名空间

Docker_第24张图片

接下来就是创建镜像仓库了

Docker_第25张图片

点击进入t1仓库

Docker_第26张图片

按照它的指引操作即可

Docker_第27张图片

#上传
sudo docker login --username=100025691051  ccr.ccs.tencentyun.com

sudo docker tag 9b9cb95443b5 ccr.ccs.tencentyun.com/thlyj/t1:v0.1

sudo docker push ccr.ccs.tencentyun.com/thlyj/t1:v0.1

Docker_第28张图片

#拉取
sudo docker pull ccr.ccs.tencentyun.com/thlyj/t1:v0.1

8、图形界面

以下是两种docker图形化界面。

portainer


Rancher


9、镜像原理

docker的镜像是由多个只读的文件系统叠加在一起形成的。当启动一个容器的时候,docker会加载这些只读层并在这些只读层的上面(栈顶)增加一个读写层。这时如果修改正在运行的容器中已有的文件,那么这个文件将会从只读层复制到读写层。该文件的只读版本还在,只是被上面读写层的该文件的副本隐藏。当删除docker,或者重新启动时,之前的更改将会消失。在Docker中,只读层及在顶部的读写层的组合被称为Union File System(联合文件系统)。


联合文件系统

联合文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。

联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。


Docker_第29张图片


镜像加载原理

bootfs(boot file system) 主要包含bootloader和kernel, bpotloader 主要是引导加载kernel,当我们加载镜像的时候,会通过bootloader加载kernal,Docker镜像最底层是bootfs,当boot加载完成后整个kernal内核都在内存中了,bootfs也就可以卸载,值得注意的是,bootfs是被所有镜像共用的,许多镜像images都是在base image(rootfs)基础上叠加的

rootfs (root file system),在bootfs之 上.包含的就是典型Linux系统中的/dev, /proc, /bin, /etc等标准目录和文件。rootfs就是 各种不同的操作系统发行版,比如Ubuntu, Centos等等 。


镜像分层原理

当我们运行一个新的容器的时候,实际上是在镜像分层的基础上新添加了一层:container layer(容器层)。之后所有容器运行时对文件系统产生的修改实际都只影响这一层。并且针对这一层所作的修改(写操作),在容器重启之后会全部丢失。所以说在使用docker的过程中,在需要修改运行时容器文件数据的时候,尽量去重新构建镜像而不是直接修改容器内文件。如果重构镜像解决不了的问题,使用数据卷。


10、Compose

Compose 简介

Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

Compose 使用的三个步骤:

  • 使用 Dockerfile 定义应用程序的环境。
  • 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
  • 最后,执行 docker-compose up 命令来启动并运行整个应用程序。

安装

#使用国内的地址下载,官方的下载太慢
curl -L https://get.daocloud.io/docker/compose/releases/download/v2.4.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

#授权
chmod +x /usr/local/bin/docker-compose

#查看是否安装成功,出现版本号就是安装成功
docker-compose --version

Docker_第30张图片

使用

1、为项目创建一个目录

 mkdir composetest
 cd composetest

2、部署的项目,这里以官网的python为例,这个简单的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

3、接下来需要一个dockerfile文件来创建镜像

Dockerfile

# syntax=docker/dockerfile:1
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:

  • 从 Python 3.7 映像开始构建映像。
  • 将工作目录设置为 。/code
  • 设置命令使用的环境变量。flask
  • 安装 gcc 和其他依赖项
  • 复制并安装 Python 依赖项。requirements.txt
  • 将元数据添加到映像,以描述容器正在侦听端口 5000
  • 将项目中的当前目录复制到映像中的工作目录。.``.
  • 将容器的默认命令设置为 。flask run

4、创建docker-compose.yml文件,定义服务

version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"

这个compose文件定义了两个服务:webredis

5、最好我们就可以启动项目了

docker-compose up

Compose 会拉取 Redis 镜像,为代码构建镜像,然后启动定义的服务。由于是从国外的网站进行下载镜像,所以会很慢,稍微等待一下即可。

6、启动完毕后,可在浏览器输入ip地址:8000服务项目了!这个项目的就是刷新页面计数。

7、按Ctrl+C 或者输入docker-compose down停止应用程序。然后修改Compose文件。

version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_ENV: development
  redis:
    image: "redis:alpine"

修改过后,修改代码就无需重新运行了,类似于热部署。此模式应仅在开发中使用。

8、现在重新启动docker-compose up,启动后访问浏览器,紧接着再修改app.py文件,这个时候刷新,会发现浏览器打印的内容改变了,变成了我们修改的内容。

return 'Hello from Docker! I have been seen {} times.\n'.format(count)

9、其他命令

#后台启动项目
docker-compose up -d

#查看后台进程
docker-compose ps

#为服务运行一次性命令
docker-compose run web

#查看帮助
docker-compose --help

#如果使用后台启动服务,可用以下命令停止服务
docker-compose stop

#关闭所有内容,完全删除容器。
docker-compose down --volumes

yml规则

3层配置,第一层是版本,第二层是服务,第三层是其他配置


编写微服务上线

如果项目出现问题,要重新部署

docker-compose up --build #重新构建

11、Swarm

简介

Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。

支持的工具包括但不限于以下各项:

  • Dokku
  • Docker Compose
  • Docker Machine
  • Jenkins

原理

如下图所示,swarm 集群由管理节点(manager)和工作节点(work node)构成。

  • swarm mananger:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。
  • work node:即图中的 available node,主要负责运行相应的服务来执行任务(task)。

Docker_第31张图片


12、拓展

Docker Machine

  • Docker Machine 是一种可以让您在虚拟主机上安装 Docker 的工具,并可以使用 docker-machine 命令来管理主机。
  • Docker Machine 可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装 docker。
  • Docker Machine 管理的虚拟主机可以是机上的,也可以是云供应商,如阿里云,腾讯云,AWS,或 DigitalOcean。
  • 使用 docker-machine 命令,可以启动,检查,停止和重新启动托管主机,也可以升级 Docker 客户端和守护程序,以及配置 Docker 客户端与主机进行通信。
  • docker-machine已经被官方弃用!不再维护更新!作为拓展知识,只需要知道有这么个东西就可以了!

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