基本概念
容器(container),镜像(image),卷(volume)
用面向对象的思想来理解,容器就是实例,镜像就是类,卷就是数据存储区。比如ubuntu:18.04
就是一个简单的镜像,用这个镜像可以按照需求创建不同的容器,一堆的容器可以共用一个卷作为某一存储区。
docker-desktop安装与配置
下载地址:https://www.docker.com/products/docker-desktop
下载后直接安装,启动的时候如果电脑条件没准备好,会有相应的提示:https://docs.docker.com/desktop/windows/troubleshoot/#virtualization
启动虚拟化
打开任务管理器-性能-CPU,查看是否开启虚拟化。如果未开启需要在BIOS界面开启。
开启WSL2
如果不使用WSL2作为后端或者已开启WSL2,可以跳过这一步。
搜索“启用或关闭Windows功能”,找到“虚拟机平台”和“适用于Linux的Windows子系统”,勾上,确定。
更新WSL2内核
启动Docker Desktop之后如果遇到如下提示,则需要安装WSL2内核的更新。
下载.msi安装后重启Docker Desktop即可解决。
文件路径
docker桌面如果使用WSL2作为后端,会在wsl中创建两个发行版用来存放数据,这两个发行版的数据文件默认存放路径为:
1 | C:\Users\[用户名]\AppData\Local\Docker\wsl\data\ext4.vhdx |
安装镜像或者在容器中安装一些库时,会存放在data下面的数据文件中,即便删除了容器或镜像也依旧存在着,需要手动清理(见后续章节)。
加速下载:设置国内镜像
打开Docker Desktop,设置,Docker Engine,在json文件中添加registry-mirrors
字段以设置国内加速镜像地址。
1 | { |
可以通过docker info
查看是否添加镜像成功。
存储控制与空间清理
随着不同镜像的定制和安装,.vhdx文件会越来越大,而且不随着镜像的删除而变小。
1 | C:\Users\[username]\AppData\Local\Docker\wsl\data\ext4.vhdx |
清理空间的手段有两种,一是针对现有文件进行压缩,另一种则是初始化归零。后者直接在Docker Desktop中-Troubleshoot-Clean / Purge data完成,前者需要通过wsl
和diskpart
命令实现。下面介绍前者——文件压缩方法。
首先通过Docker Desktop清空所有数据,得到最原始的磁盘大小,接着拉取一个镜像,可以看到磁盘体积变大。
此时把镜像删除,磁盘体积并没有发生更改。关闭Docker Desktop,接着在命令行关闭wsl并启动diskpart。
1 | wsl --shutdown |
接着在弹出的命令窗口中进行如下操作:
1 | select vdisk file="C:\Users\[username]\AppData\Local\Docker\wsl\data\ext4.vhdx" |
或者直接进行压缩操作。(可能会提示:“虚拟磁盘服务错误: 所请求的操作需要以只读方式 连接虚拟磁盘。”)
1 | select vdisk file="C:\Users\[username]\AppData\Local\Docker\wsl\data\ext4.vhdx" |
压缩完成后,重新启动Docker Desktop,再去检查文件。看到磁盘文件体积相较于压缩前有所减小,但整体仍大于一开始创建时的体积,猜测可能是存放了一些软件运行时状态导致的,无伤大雅。
常用命令行操作
查看信息
查看docker信息
1 | docker info |
查看wsl信息
1 | wsl -l -v |
查看系统空间占用
1 | docker system df |
操作镜像
Hello World - 拉取镜像,创建实例
获取镜像。从默认的镜像仓库library/ubuntu
获取标签为18.04
的镜像。
1 | docker pull ubuntu:18.04 |
运行镜像。这行命令以ubuntu:18.04
作为镜像,创建了一个容器;-it
是复合命令,意为交互式终端,-i
表示交互式,-t
表示终端,若只有-i
,则不显示终端,若只有-t
,则显示终端后无法输入;--rm
表示运行结束后删除容器,不加这个参数则需要手动删除;bash
表示容器创建后执行的命令,也可以用sh
命令。
1 | docker run -it --rm ubuntu:18.04 bash |
创建容器后,将在命令行进入linux的终端,此时输入cat /etc/os-release
,可以查看系统信息。
1 | PS C:\> docker run -it ubuntu:18.04 bash |
列出和删除镜像
列出镜像。一个镜像可以对应多个标签(TAG),如下面例子最下方两个所示,唯一标识符是ID。
只列出ID,只需加上-q
参数。
1 | docker image ls |
上方镜像列表有一行为
<none>
,意为“悬虚镜像(dangling image)”,没有实际价值,可以通过命令docker image prune
删除。关于中间层镜像、筛选列出、以特定格式显示等更丰富的功能,后续用到再补充。
删除镜像:根据列出的镜像ID、名称等进行删除,可以搭配列出使用。
1 | docker image rm redis # 删除名称包含redis的镜像 |
定制镜像
定制镜像前,先来做这么一个实践:拉取一个nginx的镜像,启动作为web服务器,并修改其中首页的内容。
1 | docker pull nginx # 拉取镜像 |
执行完以上两步,打开浏览器输入127.0.0.1
,可以看到nginx的首页。
可以通过如下命令查看首页的页面代码:
1 | docker exec -it webserver /bin/bash # 进入容器操作终端 |
使用以下命令修改首页内容。
1 | /bin/echo '<h1>Hello, World</h1>' > /usr/share/nginx/html/index.html |
此时再进入浏览器,刷新页面后看到内容发生了改变。
将以上的步骤记录下并保存到Dockerfile
中,即完成了镜像的定制。创建一个空目录,添加名为Dockerfile
的文本文件,在其中写入:
1 | FROM nginx |
接着在该目录下打开终端,输入如下命令构建镜像。注意最后的.
表示当前路径,作为构建的上下文(context),不可遗漏。
1 | docker build -t nginx:my-build . |
查看镜像列表,可以看到我们刚刚创建的镜像,名为nginx
,标签是my-build
。
1 | docker image ls -a |
运行一个容器,并进入浏览器查看,即可看到,通过定制化后的镜像运行的容器,首页内容已经是我们想要的样式。
1 | docker run -d -p 8080:80 nginx:my-build |
关于定制镜像的更多内容请参考教程:https://vuepress.mirror.docker-practice.com/image/build/
操作容器
Hello World - 创建容器,列出容器,删除容器
创建容器。根据某个镜像创建容器,接着执行一条命令,执行完退出容器。
1 | docker run ubuntu:18.04 /bin/echo "Hello World" |
列出容器:
1 | docker container ls # 列出正在运行的容器 |
删除容器。根据列出的容器ID或名称,删除一个或多个容器。
1 | docker container rm 72c82c8a430b 009cab741133 fc3a75dbaff4 |
删除没有在运行的容器
1 | docker container prune |
运行持久化
run
命令用于创建容器后执行一条命令,持久化运行有两种情形,一是执行的命令存在无限循环,二是使用了交互式终端-it
。
后台运行和进入容器
后台运行只需要在启动时加上参数-d
,配合交互式终端保持持久化,命令如下:
1 | docker run -dit ubuntu:18.04 |
返回一个ID,可以通过如下命令重新进入运行的容器中:
1 | docker exec -it 5ffeb933aab /bin/bash |
终止和重新启动容器
1 | docker container stop 5ffeb933aab |
指定名称
--name
1 | docker run --name my_container -d ubuntu:18.04 |
暴露端口
暴露指定端口:-p
+ hostPort:containerPort
1 | docker run --name my_container -p 80:80 -d ubutntu:18.04 |
更详细的用法用到再补充。
Docker + VSCode构建一个python开发环境
创建包含python开发环境的容器
拉取镜像
1 | docker pull python:slim |
创建容器
1 | docker run -dit --name py python:slim |
进入终端查看
1 | docker exec -it py bash |
使用VS Code一键在容器中运行脚本
python程序安装完,如何调用其中的解译器运行我们的.py脚本?
方法一:直接在容器中创建脚本,编写代码(不建议这么干,因为除了脚本还可能有数据,并不推荐向容器中写入数据);
方法二:挂载一个容器外部的代码文件夹,编写完代码进入容器运行代码;
很显然方法二是一个很不错的方案,但是仍有一点欠缺,能否在编写完脚本代码后通过一个简单的操作,将代码文件在容器内的解译器中编译执行?很显然,这个操作是存在的,借助Visual Studio Code Remote - Containers扩展,“在容器中打开当前文件夹”,即可在VS Code中编写完代码后,直接点击一个运行按钮来调用容器内的python解译器来执行脚本。
安装完扩展Visual Studio Code Remote - Containers后,创建一个文件夹,写入一个main.py,输入以下代码:
1 | def main(): |
接着在文件目录添加文件Dockerfile
,写入:
1 | FROM python:slim |
接着打开左侧的“远程资源管理器”或按下快捷键Ctrl + Shift + P,找到Open Folder in Container,点击后选择脚本代码所在的文件夹,然后选择From ‘Dockerfile’,VSCode就会自动检测目录下的Dockerfile并以此重新构建一个镜像并创建卷(如果不存在名为vscode的卷的话),接着创建一个容器并启动它,此时的左下角就会有如下提示
在VSCode中打开终端,可以看到终端路径已经是容器中的路径了。运行脚本,就相等于在容器中运行。
使用Nginx镜像快速搭建一个静态服务器
知识点:挂载静态文件路径和配置文件路径
参考:https://vuepress.mirror.docker-practice.com/appendix/repo/nginx/
拉取nginx镜像:
1 | docker pull nginx |
nginx的配置文件入口:/etc/nginx/nginx.conf
;
nginx服务器配置文件目录:/etc/nginx/conf.d/
,其中的所有.conf
文件都会被nginx.conf
引用(include)进来;
nginx默认的静态目录:/usr/share/nginx/html/
;
挂载磁盘目录
使用--mount
关键字
1 | docker run -d -p 3303:80 --name webserver --mount type=bind,source=D:\dist,target=/usr/share/nginx/html,readonly --mount type=bind,source=D:\nginx\conf.d,target=/etc/nginx/conf.d nginx |
以上命令:创建一个名为webserver
的容器;绑定容器的80端口到本机的3303;挂载本机D:\dist
目录为容器的/usr/share/nginx/html
目录,容器权限为只读;挂载本机D:\nginx\conf.d
目录为容器的/etc/nginx/conf.d
目录,默认权限为读和写;使用的镜像名称为nginx。
挂载目录也可以挂载单个文件,docker会根据sourse指定的路径判断是文件还是文件夹。
以上挂载的配置可以通过docker inspect webserver
查看:
1 | docker inspect webserver |
除了使用--mount
关键字,还可以用-v
关键字,写法更简便
1 | docker run -d -p 3303:80 --name webserver -v D:\dist:/usr/share/nginx/html:ro -v D:\nginx\conf.d:/etc/nginx/conf.d nginx |
查看挂载配置:
1 | docker inspect webserver |