1. 参考资料
官方文档:https://docs.docker.com/docker-for-windows/
仓库地址:https://hub.docker.com/
2. Docker概述
2.1 Docker为什么会出现
一款产品,开发和上线两套环境,应用环境配置费时费力,而且容易出问题
尤其对于机器学习和深度学习的库更是如此,很可能存在版本问题、底层依赖冲突问题
所以发布项目时,不只是一套代码过去,而是代码+环境整体打包过去
所谓开发即运维,保证系统稳定性,提高部署效率
使用Docker后的流程:
开发:建立模型–环境–打包带上环境,即镜像–放到Docker仓库
部署:下载Docker中的镜像,直接运行即可
Docker的思想来自于集装箱,集装箱,对环境进行隔离
Docker通过隔离机制,可以将服务器利用到极致。
2.2 Docker的历史
2010年,几个搞IT的人,在美国成立一家公司dotCloud
做一些pass的云计算服务
他们将自己的容器化技术命名为Docker
Docker基于Go语言开发
Docker刚刚诞生的时候,没有引起行业的注意,dotCloud活不下去
然后他们决定开源
2013年,创始人将Docker开源,不开则以,一开惊人,刚开源的时候,每个月都会更新一个版本
2014年4月9日,Docker 1.0发布
2.3 容器VS虚拟机
虚拟机原理
缺点:
- 资源占用多
- 冗余步骤多
- 启动很慢
容器化技术
比较虚拟机和Docker的不同
传统虚拟机 | Docker | |
---|---|---|
虚拟内容 | 硬件+完整的操作系统+软件 | APP+LIB |
大小 | 笨重,通常几个G | 轻便几个M或KB |
启动速度 | 慢,分钟级 | 快,秒级 |
2.4 Docker基本组成
明确几个概念:
-
镜像(image):docker镜像好比一个模板,可以通过这个模板来创建容器(container),一个镜像可以创建多个容器,类似Python中的Class
-
容器(container):类似Python中通过Class创建的实例,Object;容器可以理解为一个简易的系统
-
仓库(repository):存放镜像的地方,
分为共有仓库和私有仓库
-
Docker Hub:国外的
-
阿里云:配置镜像加速
-
3. Dokcer安装
3.1 卸载旧版本
# 卸载旧的Docker版本
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
3.2 安装基本包
# 安装基本的安装包
$ sudo yum install -y yum-utils
3.3 设置镜像仓库
#设置镜像仓库
# 不要用官网默认这个!
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo # 默认是国外的
# 换成下面的
$ sudo yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 阿里云镜像
3.4 更新软件包索引
yum makecache fast
3.5 安装Docker引擎
yum install docker-ce docker-ce-cli containerd.io # docker-ce 社区版 ee 企业版
注意这里会有几个个y/n的判断
要看到Complet再收手!
3.6 启动Docker
systemctl start docker # 代表启动成功
3.7 卸载Docker
# 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 删除资源
rm -rf /var/lib/docker # docker 的默认工作路径
3.8 阿里云镜像加速
控制台搜索 容器镜像服务 找到加速地址
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://hkvtc6o9.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
4. Docker原理
Docker是一个Client-Server结构的系统,Docker的守护进程在主机上。通过Socket从客户端访问!
DockerServer接受来自Docker-Client的指令,
Docker为什么比VM快?
- Docker有着比虚拟机更少的抽象层
- docker主要用的是宿主机的内核,vm需要Guest OS
5. Docker命令
5.1 帮助命令
docker version # 显示docker的基本信息docker info # 系统信息,镜像和容器的数量docker --help # 全部信息
5.2 镜像命令
docker images
查看本地主机上的所有镜像
REPOSITORY # 镜像仓库源
TAG # 镜像的标签
IMAGE ID # 镜像的ID
CREATED # 镜像的创建时间
SIZE # 镜像的大小
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
Options:
-a, --all Show all images (default hides intermediate images)
–digests Show digests
-f, --filter filter Filter output based on conditions provided
–format string Pretty-print images using a Go template
–no-trunc Don’t truncate output
-q, --quiet Only show image IDs
docker search
搜索仓库中的镜像,相当于网页搜索
Usage: docker search [OPTIONS] TERM
Options:
-f, --filter filter Filter output based on conditions provided
–format string Pretty-print search using a Go template
–limit int Max number of search results (default 25)
–no-trunc Don’t truncate output
举例:
docker search mysql --filter=STARS=3000 # 搜索出Stars大于3000的
docker pull
下载镜像
#下载镜像 #docker pull 镜像名[:tag] 不写tag默认最新版[root@192 ~]# docker pull mysql
docker rmi
remove images
# 删除一个 可以通过名称 也可以指定id -f表示删除所有docker rmi -f 9cfcce23593a# 删除多个 用空格分隔iddocker rmi -f [id] [id] [id]# 删除所有 docker rmi -f $(docker images -aq) # images -aq就是查所有镜像id,从而递归删除
5.3 容器命令
新建容器并启动
docker run [可选参数] image# 参数说明--name=“Name” # 容器名字,用于区分容器-d #后台方式运行-it #使用交互方式运行,进入容器查看内容-p #指定容器的端口 如-p 8080::8080 -p ip:主机端口:容器端口 -p 主机端口:容器端口 -p 容器端口 容器端口-P #随机指定端口
查看容器
# 查看正在运行的容器docker ps# 查看曾经运行的容器docker ps -a# 显示最近创建的容器,设置显示个数docker ps -a - n=? # 只显示容器的编号docker ps -aq
退出容器
# 容器停止退出exit# 容器不停止退出 注意必须在英文输入法下,中文输入法不行Ctrl + P + Q
删除容器
# 删除指定容器 不能删除正在运行的容器,如果强制删除 rm -fdocker rm 容器id# 删除所有容器docker rm -f $(docker ps -aq)# 删除所有容器docker ps -a -q|xargs docker rm
启动和停止容器
docker start 容器IDdocker restart 容器IDdocker stop 容器IDdocker kill 容器ID
进入容器
# 启动容器并进入容器docker run -it centos /bin/bash
或者
#进入当前正在运行的容器docker exec -it 容器ID /bin/bash
或者
docker attach 容器ID# 区别# docker exec # 进入容器后开启一个新的终端,可以在里面操作(常用)# docker attach 进入容器正在执行的终端,不会启动新的进程
5.4 其他命令
后台启动docker
docker run -d 镜像名# 用docker ps 查看的时候 发现停止了# 后台运行,docker发现前台没有,容器启动后,发现自己没有提供服务,会立刻停止
Last login: Wed Jun 17 19:47:35 2020[root@192 ~]# systemctl start docker # 关机后重启了,需要启动docker[root@192 ~]# docker run -d centos # 运行8ce188e5fee31c2fac93c0a405ee1a95c38dbc50cb47c35b19c0039c27558ded[root@192 ~]# docker ps -a # 查看正在运行的CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES8ce188e5fee3 centos "/bin/bash" 19 seconds ago Exited (0) 18 seconds ago tender_dirac7b1a7dd10ea4 centos "/bin/bash" 8 hours ago Exited (0) 8 hours ago fervent_mirzakhani
查看日志
常用命令
docker logs -f -t --tail n 【id】
指南
[root@192 ~]# docker logs --helpUsage: docker logs [OPTIONS] CONTAINERFetch the logs of a containerOptions: --details Show extra details provided to logs -f, --follow Follow log output --since string Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes) --tail string Number of lines to show from the end of the logs (default "all") -t, --timestamps Show timestamps # 时间戳 --until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
查看容器中进程信息
docker top 容器ID
查看正在运行的容器信息(镜像的元数据)
docker inspect 容器ID
从容器内拷贝文件到主机上
docker cp 容器ID:目录 主机目录#举例docker cp 0569081aa89c:/home/test.java /home# 拷贝是一个手动过程,未来我们使用 -v 卷的技术,可以实现自动同步 /home /home
查看内容占用
docker stats
5.5 小结
6. 作业练习
6.1 部署nginx
下载镜像
docker pull nginx
运行测试
# -d 后台运行,--name 命名,-p 暴露端口,3344服务器、宿主机的端口,容器内部端口docker run -d --name nginx01 -p:3344:80 nginx
内网访问
curl localhost:3344
也可以用公网访问
6.2 部署tomcat
docker pull tomcat:9.0 # 之前下过了,应该不用下了,这里老师讲错了
# 启动运行,应该加上版本号docker run -d -p 3355:8080 --name tomcat01 tomcat
# 进入容器docker exec -it tomcat01 /bin/bash
发现问题
- linux命令少了
- 没有webapps
这是阿里云镜像的原因:默认使用最小镜像,所有不必要的都剔除了,保证最小可运行环境
6.3 es+kibana
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
7 Docker镜像
7.1 原理
UnionFS 联合文件系统
bootfs:boot file system
rootfs:root file system
Docker镜像都是只读的,当容器启动时,一个新的可写层被加到镜像的顶部,这一层就是我们通常说的容器层,容器层之下的都叫镜像层
7.2 commit提交镜像
docker commit # 提交容器成为一个新的副本docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]
8. 容器数据卷
8.1 什么是容器卷
docker是要将应用和环境打包成一个镜像
这样,数据就不应该在容器中,否则容器删除,数据就会丢失,这就是删库跑路
故容器之间要有一个数据共享技术
在Docker容器中产生的数据,同步到本地,这就是卷技术
本质上是一个目录挂载,将容器内的目录挂载到虚拟机上
目的:容器的持久化和同步操作
容器间可以数据共享
8.2 使用数据卷
方式一:直接使用命令来挂载
docker run -it -v -p# -it 交互式进入# -v volume卷技术# -p 主机端口
8.3 实战安装mysql
docker search mysql# 拉取docker pull mysql:5.7# 挂载docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.-d 后台运行-p 端口映射-v 卷挂载-e 环境配置 安装启动mysql需要配置密码--name 容器名字
注意记得要开端口号
8.4 具名和匿名挂载
# 匿名挂载-v 容器内路径!$ docker run -d -P --name nginx01 -v /etc/nginx nginx# 查看所有的volume(卷)的情况$ docker volume ls DRIVER VOLUME NAME # 容器内的卷名(匿名卷挂载)local 21159a8518abd468728cdbe8594a75b204a10c26be6c36090cde1ee88965f0d0local b17f52d38f528893dd5720899f555caf22b31bf50b0680e7c6d5431dbda2802c # 这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路径!# 具名挂载 -P:表示随机映射端口$ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx9663cfcb1e5a9a1548867481bfddab9fd7824a6dc4c778bf438a040fe891f0ee# 查看所有的volume(卷)的情况$ docker volume ls DRIVER VOLUME NAMElocal 21159a8518abd468728cdbe8594a75b204a10c26be6c36090cde1ee88965f0d0local b17f52d38f528893dd5720899f555caf22b31bf50b0680e7c6d5431dbda2802clocal juming-nginx #多了一个名字# 通过 -v 卷名:查看容器内路径# 查看一下这个卷$ docker volume inspect juming-nginx[ { "CreatedAt": "2020-05-23T13:55:34+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data", #默认目录 "Name": "juming-nginx", "Options": null, "Scope": "local" }]
所有的docker容器内的卷,没有指定目录的情况下都是在**/var/lib/docker/volumes/自定义的卷名/_data**下,
如果指定了目录,docker volume ls 是查看不到的。
区分三种挂载方式
三种挂载: 匿名挂载、具名挂载、指定路径挂载
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载 docker volume ls 是查看不到的
# 通过 -v 容器内路径: ro rw 改变读写权限ro #readonly 只读rw #readwrite 可读可写$ docker run -d -P --name nginx05 -v juming:/etc/nginx:ro nginx$ docker run -d -P --name nginx05 -v juming:/etc/nginx:rw nginx# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作!
8.5 Dockerfile
Dockerfile 就是用来构建docker镜像的构建文件!命令脚本!先体验一下!
通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个个的命令,每个命令都是一层!
# 创建一个dockerfile文件,名字可以随便 建议Dockerfile# 文件中的内容: 指令(大写) + 参数$ vim dockerfile1 FROM centos # 当前这个镜像是以centos为基础的 VOLUME ["volume01","volume02"] # 挂载卷的卷目录列表(多个目录) 匿名挂载 CMD echo "-----end-----" # 输出一下用于测试 CMD /bin/bash # 默认走bash控制台
# 构建出这个镜像# 构建出这个镜像 -f dockerfile1 # f代表file,指这个当前文件的地址(这里是当前目录下的dockerfile1) -t caoshipeng/centos # t就代表target,指目标目录(注意caoshipeng镜像名前不能加斜杠‘/’) . # 表示生成在当前目录下$ docker build -f dockerfile1 -t caoshipeng/centos .
# 查看自己构建的镜像$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEcaoshipeng/centos latest f4a6b0d4d948 About a minute ago 237MB
#启动自己写的容器镜像$ docker run -it f4a6b0d4d948 /bin/bash # 运行自己写的镜像$ ls -l # 查看目录
这个卷和外部一定有一个同步的目录
查看一下卷挂载
# docker inspect 容器id$ docker inspect ca3b45913df5
这种方式使用的十分多,因为我们通常会构建自己的镜像!
假设构建镜像时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径!
8.6 数据卷容器
多个MySQL同步数据!
命名的容器挂载数据卷!
# 测试 启动3个容器,通过刚才自己写的镜像启动# 创建docker01:因为我本机是最新版,故这里用latest,狂神老师用的是1.0如下图$ docker run -it --name docker01 caoshipeng/centos:latest# 查看容器docekr01内容$ lsbin home lost+found opt run sys vardev lib media proc sbin tmp volume01etc lib64 mnt root srv usr volume02# 不关闭该容器退出CTRL + Q + P # 创建docker02: 并且让docker02 继承 docker01$ docker run -it --name docker02 --volumes-from docker01 caoshipeng/centos:latest# 查看容器docker02内容$ lsbin home lost+found opt run sys vardev lib media proc sbin tmp volume01etc lib64 mnt root srv usr volume02
# 再新建一个docker03同样继承docker01$ docker run -it --name docker03 --volumes-from docker01 caoshipeng/centos:latest$ cd volume01 #进入volume01 查看是否也同步docker01的数据$ ls docker01.txt# 测试:可以删除docker01,查看一下docker02和docker03是否可以访问这个文件# 测试发现:数据依旧保留在docker02和docker03中没有被删除
多个mysql实现数据共享
$ docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7$ docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7# 这个时候,可以实现两个容器数据同步!
结论:
容器之间的配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!
9. Dockerfile
9.1 DockerFile介绍
dockerfile
是用来构建docker镜像的文件!命令参数脚本!
构建步骤:
1、 编写一个dockerfile文件
2、 docker build 构建称为一个镜像
3、 docker run运行镜像
4、 docker push发布镜像(DockerHub 、阿里云仓库)
9.2 DockerFile构建过程
基础知识:
1、每个保留关键字(指令)都是必须是大写字母
2、执行从上到下顺序
3、#表示注释
4、每一个指令都会创建提交一个新的镜像曾,并提交!
Dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!
Docker镜像逐渐成企业交付的标准,必须要掌握!
DockerFile:构建文件,定义了一切的步骤,源代码
DockerImages:通过DockerFile构建生成的镜像,最终发布和运行产品。
Docker容器:容器就是镜像运行起来提供服务。
9.3 DockerFile的指令
FROM # from:基础镜像,一切从这里开始构建MAINTAINER # maintainer:镜像是谁写的, 姓名+邮箱RUN # run:镜像构建的时候需要运行的命令ADD # add:步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录WORKDIR # workdir:镜像的工作目录VOLUME # volume:挂载的目录EXPOSE # expose:保留端口配置CMD # cmd:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代ENTRYPOINT # entrypoint:指定这个容器启动的时候要运行的命令,可以追加命令ONBUILD # onbuild:当构建一个被继承DockerFile这个时候就会运行onbuild的指令,触发指令COPY # copy:类似ADD,将我们文件拷贝到镜像中ENV # env:构建的时候设置环境变量!
9.4 实战测试
scratch 镜像
FROM scratchADD centos-7-x86_64-docker.tar.xz /LABEL \ org.label-schema.schema-version="1.0" \ org.label-schema.name="CentOS Base Image" \ org.label-schema.vendor="CentOS" \ org.label-schema.license="GPLv2" \ org.label-schema.build-date="20200504" \ org.opencontainers.image.title="CentOS Base Image" \ org.opencontainers.image.vendor="CentOS" \ org.opencontainers.image.licenses="GPL-2.0-only" \ org.opencontainers.image.created="2020-05-04 00:00:00+01:00"CMD ["/bin/bash"]
Docker Hub 中 99%的镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行构建。
创建一个自己的centos
# 1./home下新建dockerfile目录$ mkdir dockerfile# 2. dockerfile目录下新建mydockerfile-centos文件$ vim mydockerfile-centos# 3.编写Dockerfile配置文件FROM centos # 基础镜像是官方原生的centosMAINTAINER cao<1165680007@qq.com> # 作者ENV MYPATH /usr/local # 配置环境变量的目录 WORKDIR $MYPATH # 将工作目录设置为 MYPATHRUN yum -y install vim # 给官方原生的centos 增加 vim指令RUN yum -y install net-tools # 给官方原生的centos 增加 ifconfig命令EXPOSE 80 # 暴露端口号为80CMD echo $MYPATH # 输出下 MYPATH 路径CMD echo "-----end----" CMD /bin/bash # 启动后进入 /bin/bash# 4.通过这个文件构建镜像# 命令: docker build -f 文件路径 -t 镜像名:[tag] .$ docker build -f mydockerfile-centos -t mycentos:0.1 .# 5.出现下图后则构建成功
$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEmycentos 0.1 cbf5110a646d 2 minutes ago 311MB# 6.测试运行$ docker run -it mycentos:0.1 # 注意带上版本号,否则每次都回去找最新版latest$ pwd /usr/local # 与Dockerfile文件中 WORKDIR 设置的 MYPATH 一致$ vim # vim 指令可以使用$ ifconfig # ifconfig 指令可以使用# docker history 镜像id 查看镜像构建历史步骤$ docker history 镜像id
我们可以列出本地进行的变更历史
我们平时拿到一个镜像,可以用 “docker history 镜像id” 研究一下是什么做的
CMD 和 ENTRYPOINT区别
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代。ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
测试cmd
# 编写dockerfile文件$ vim dockerfile-test-cmdFROM centosCMD ["ls","-a"] # 启动后执行 ls -a 命令# 构建镜像$ docker build -f dockerfile-test-cmd -t cmd-test:0.1 .# 运行镜像$ docker run cmd-test:0.1 # 由结果可得,运行后就执行了 ls -a 命令....dockerenvbindevetchome# 想追加一个命令 -l 成为ls -al:展示列表详细数据$ docker run cmd-test:0.1 -ldocker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\":executable file not found in $PATH": unknown.ERRO[0000] error waiting for container: context canceled # cmd的情况下 -l 替换了CMD["ls","-l"] 而 -l 不是命令所以报错
测试ENTRYPOINT
# 编写dockerfile文件
$ vim dockerfile-test-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]
# 构建镜像
$ docker build -f dockerfile-test-entrypoint -t cmd-test:0.1 .
# 运行镜像
$ docker run entrypoint-test:0.1
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found ...
# 我们的命令,是直接拼接在我们得ENTRYPOINT命令后面的
$ docker run entrypoint-test:0.1 -l
total 56
drwxr-xr-x 1 root root 4096 May 16 06:32 .
drwxr-xr-x 1 root root 4096 May 16 06:32 ..
-rwxr-xr-x 1 root root 0 May 16 06:32 .dockerenv
lrwxrwxrwx 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x 5 root root 340 May 16 06:32 dev
drwxr-xr-x 1 root root 4096 May 16 06:32 etc
drwxr-xr-x 2 root root 4096 May 11 2019 home
lrwxrwxrwx 1 root root 7 May 11 2019 lib -> usr/lib
lrwxrwxrwx 1 root root 9 May 11 2019 lib64 -> usr/lib64 ....
Dockerfile中很多命令都十分的相似,我们需要了解它们的区别,我们最好的学习就是对比他们然后测试效果!