Docker入门教程
前言
之前发过一篇有关Docker命令的文章,但感觉太水了,也不能系统地学习Docker这门技术,并且之前也只是会用,自己并不会构建Docker的镜像,并且很多命令行的操作并不习惯,所以现在重新系统的学习一下Docker,从使用到构建一个自己的Docker镜像
这篇文章并不是0基础学习Docker的文章,建议有过使用NAS上的Docker经验再看,这样能更快理解在做什么
安装Docker
Docker主要是Linux中使用,我接触Docker是因为NAS,大多是有图形化界面,结果发现自己并不熟悉在命令行配置Docker,所以这次我会使用Ubuntu重新学习使用Docker,细教程可以看Docker官方文档,这里不再赘述
安装好后可以通过下面的命令测试一下Docker
1 | docker -v |
配置镜像加速
如果使用的是非大陆地区的VPS,那么下面的步骤可以跳过了,换源后可能导致速度下降!!!
1 | sudo mkdir -p /etc/docker |
其中https://xxx.com
需要换成镜像地址,我收集了几个放在下面
镜像源 | 地址 |
---|---|
Docker官方镜像源 | https://registry.docker-cn.com |
中国科学技术大学 | https://docker.mirrors.ustc.edu.cn |
腾讯镜像源 | https://mirror.ccs.tencentyun.com |
网易镜像源 | http://hub-mirror.c.163.com |
使用Docker
查看帮助文档
这个是最基础的命令,以后可以快速回忆起命令
查看docker所有命令的帮助文档
1 | docker --help |
查看pull命令的帮助文档
1 | docker pull --help |
类似的还可以查看ps
、run
等命令的具体稳定
但这里的说明往往比较简略,需要详细的说明可以在官方文档中查看,本文只会介绍一血常用的命令
搜索命令
通过这个命令可以快速的找一些别人公开到镜像仓库的镜像,例如我需要一个mysql数据库的镜像
1 | docker search mysql |
当然,这种在命令行之间查找的方式并不方便,因此也可以直接通过网页查询https://hub.docker.com
下载镜像
找到了需要的镜像,那么就要下载下来,就需要用到docker pull
这个命令:
1 | docker pull <镜像仓库地址>/<镜像名>:<标签> |
有两点需要注意:
- 镜像仓库地址可以不指定,若不指定镜像仓库地址,则默认从Docker官方镜像仓库中查询
- 镜像标签可以不指定,若不指定镜像标签,则默认使用标签latest
假设我需要从官方仓库中下载一个mysql版本为5.7镜像:
1 | docker pull mysql:5.7 |
列出镜像信息
如果需要看当前的机器上下载了哪些镜像,可以通过下面的命令:
1 | docker images |
可以看到所有镜像的5条信息:镜像名、镜像标签、镜像ID、镜像创建时间、镜像大小
如果需要列出所有镜像(默认隐藏的镜像),可以使用参数-a
(–all):
1 | dock images -a |
如果需要列出所有镜像名以busy
开头并且标签以libc
结尾的镜像可以使用参数-f
(–filter):
1 | docker -a -f=reference='busy*:*libc' |
列出容器信息
默认情况下列出的是正在运行的容器的信息,若容器已经停止,则不会列出:
1 | docker ps |
如果需要列出所有容器,可以使用参数-a
:
1 | docker ps -a |
如果要列出所有推出的容器也可以使用过滤器-f
1 | docker ps -f "status=exited" |
创建并运行命令
1 | docker run <可选项> <容器名> <命令> <命令参数> |
- 可选项:主要有
-d
、-p
、-v
、-e
、--restart
这几个选项 - 容器名:若没有标签,则默认使用的标签为
latest
,若本机没有目标镜像则会自动下载 - 命令:容器创建后需要执行的命令
- 命令参数:上面执行命令的参数
例如,我需要运行一个版本为5.7的mysql镜像:
1 | docker run mysql:5.7 |
上面提供了一个最简的运行容器的方式,接下来将对参数具体说明
容器运行方式
默认运行
docker run
默认的运行方式是由镜像中设置的,如果需要自定义,可以设置<可选项>
的参数
后台运行
在<可选项>
中添加一个参数-d
这里提供一个后台运行mysql镜像容器的例子:
1 | docker run -d mysql |
交互式运行
这种运行方式主要是在调试时使用
在<可选项>
中添加一个参数it
-i
:以交互式运行容器,通常与-t
同时使用-t
:启动容器后为容器分配一个命令行,通常与-i
同时使用
一般进入容器后需要使用bash
作为命令解析器,所以使用交互式的运行方式会导致配置镜像时设置的CMD
命令失效
这里还是提供一个以交互式运行的例子:
1 | docker run -it mysql:6.1 bash |
对外发布端口
在<可选项>
中添加一个参数-p
(–port):
1 | docker run -p <宿主机端口>:<容器端口> <镜像名>:<镜像标签> |
假设需要将nginx的80、443端口分别映射到主机的88、8443端口:
1 | docker run -p 88:80 -p 8443:443 nginx:latest |
在有需要的情况下可以声明使用tcp还是udp协议,若不声明,默认使用tcp
1 | docker run -p 88:80/tcp -p 88:80/udp nginx:latest |
映射数据卷
在<可选项>
中添加一个参数-v
(–volume):
1 | docker run -v <宿主机路径>:<容器路径>:<读写权限> <镜像名>:<镜像标签> |
读写权限为可选项:
- ro(read-only):容器对文件只读不可写
- rw(read-write):容器对文件既可读也可写
- 默认:当不配置权限是默认为rw
和端口类似,同一个容器也可以映射多个数据卷
设置环境变量
在<可选项>
中添加一个参数-e
(–enviroment):
1 | docker run -e <环境变量名名>=<环境变量值> <镜像名>:<镜像标签> |
和端口、数据卷类似,同一个容器也可以配置多个环境变量
设置容器名
在<可选项>
中添加一个参数--name
:
1 | docker run --name <容器名> <镜像名>:<镜像标签> |
设置容器重启策略
在<可选项>
中添加一个参数--restart
:
1 | docker run --restart <重启策略> <镜像名>:<镜像标签> |
重启策略
主要有以下几种:
- no:容器退出时不会自动重启
- always:容器总是在退出后自动重启
- on-failure[:max-retries]:容器仅在非正常退出时重启,可以指定最大重试次数
- unless-stopped:容器会在推出后自动重启,除非手动停止了容器
- 默认策略:no
进入容器内部执行命令
有时候我们需要进入容器内部执行一些命令检查一下运行状态,需要进入容器内部,就需要这个命令:
1 | docker exec <可选项> <容器ID或容器名> <命令> <命令参数> |
假设我们需要查看容器名为my-nginx
的文件就可以使用下面这段命令:
1 | docker exec my-nginx ls -a |
这种方式每次只能使用一个命令,比较繁琐,还有一种“进入”容器”内部的方式,类似于创建容器时的以交互式运行的方法,这里需要增加一个参数-it
:
1 | docker exec -it my-nginx bash |
此时想要“从容器出来”就可以直接输入:
1 | exit |
与直接以交互式方式运行容器不同的是,这样退出容器后,该容器依旧在后台运行
查看容器日志
有时候我们需要查看程序运行的日志,一般容器是以后台方式运行的,想要查看日志,除了直接进入容器内部查看,还可以使用下面的命令:
1 | docker logs <可选项> <容器ID或容器名> |
如果需要持续查看日志可以增加一个参数-f
(–follow):
1 | docker logs -f my-nginx |
如果只想查看最新的20条日志,可以增加一个参数-n
(–tail):
1 | docker logs -n 20 my-nginx |
容器和宿主机之间的文件拷贝
把容器中的文件拷贝到宿主机中
1 | docker cp <容器ID或容器名>:<容器中的文件路径> <宿主机目标地址路径> |
把宿主机中的文件拷贝到容器中
1 | docker cp <宿主机的文件路径> <容器ID或容器名>:<容器中的目标路径> |
停止容器
1 | docker stop <可选项> <容器ID或容器名...> |
可以同时填写多个容器同时停止这些容器
继续运行容器
1 | docker start <可选项> <容器ID或容器名> |
docker start
和docker run
的区别在于前者是运行一个已创建但停止的容器,后者是创建一个新的容器并运行
删除容器
1 | docker rm <可选项> <容器ID或容器名...> |
假设需要删除一个容器ID为111
和222
两个容器
1 | docker rm 111 222 |
需要注意的是,这种方式并不能删除正在运行的容器,可以先停止容器或使用参数-f
(–force)强制删除容器
1 | docker rm -f my-nginx |
如果想要删除所有容器,需要提前了解一下Linux中$()
命令替换的知识,我们可以通过docker ps -aq
获取所有容器的容器ID,需要删除一个容器就是docker rm <容器ID>
,所以删除所有容器就是
1 | docker rm -f $(docker ps -aq) |
如果想要删除所有状态为退出的容器也是类似的:
1 | docker rm $(docker ps -q -f "status=exited") |
Docker网络
虽然默认情况下容器和容器可以进行网络通信,但每次创建容器都是Docker给容器分配的IP地址,这使得我们使用起来不太方便。这种情况我们可以通过创建一个自定义网络来解决这些问题,把需要互相联通的容器加入同一个网络中,这样容器之间可以通过容器名代替IP地址进行连接访问(其实就是Docker会自动把容器名作为一个域名去解析成对应的IP地址)
创建网络
1 | docker network create <网络名> |
创建完之后可以通过下面这个命令查看目前有几个Docker网络
1 | docker network ls |
加入网络
创建容器时加入
在<可选项>
中添加一个参数--network
:
1 | docker run --network <网络名> <镜像名>:<镜像标签> |
将已创建的容器加入网络
1 | docker network connect <可选项> <网络名> <容器ID或镜像名> |
删除网络
1 | docker network rm <网络名> |
DockerFile
前面主要学习了如何使用别人已经构建好的Docker镜像,这一节主要讲解如何自己构建一个Docker镜像。可以将Docker理解成一个虚拟机,而这个虚拟机是通过DockerFile构建的,容器启动后会按照DockerFile的设置运行相关程序
基本语法
- 不区分大小写,但是习惯大写
- 基本以
FROM
指令开头 - 用
#
表示注释
快速入门
这里先构建一个最简单的Helloworld镜像,其目的是输出字符串Hello World
,在Linux中想要在终端中打印某个字符可以用echo
- 先创建一个Dokckerfile文件
1 | vim Dockerfile |
- 编写Dockerfile
1 | FROM ubuntu:22.04 |
- 编译镜像
1 | docker build -t helloworld:1.0 -f Dockerfile . |
- 参数
-t
代表tag标签,后面接着就是docker名和标签 - 参数
-f
(file)后面接着是dockerfile的名称,最开始我们创建了一个叫Dockerfile
的文件,所以我们这里就写Dockerfile
- 后面是
Dockerfile
的路径,因为我们是在当前目录下创建的,所以写.
稍等片刻,一个叫helloworld:1.0
的镜像就会出现,可以通过docker image -a
显示本机所有镜像,然后可以尝试运行一下自己构建的docker:
1 | docker run helloworld:1.0 |
不出意外的话,终端就会输出对应字符
但使用docker ps
应该找不到刚刚启动的容器,因为容器已经退出了,这里简单讲一下容器的生命周期:docker容器运行必须有一个前台进程,如果没有前台进程执行,容器就认为空闲,就会自行退出,刚刚启动的容器在运完echo “Hello World”
后前台已经没有进程了,就自行退出了
常用指令
FROM
- 说明:指定基础镜像,基于哪个镜像做变更
- 用法:
FROM <镜像名>:<镜像标签>
- 作用时机:构建镜像时
CMD
- 说明:定义容器运行时的默认命令,可以在使用
docker run
的时候覆盖掉CMD中定义的命令 - 用法:
CMD [“<命令>”,“<参数1>”,“<参数2>”,...]
(命令和参数作为json数组的元素去书写)或CMD <命令> <参数1> <参数2> ...
(前者形式不能解析环境变量,后者可以);一个Dockerfile中有多个CMD,那么只有最后一个生效 - 作用时机:容器运行时
以下面这个基础的镜像作为例子:
1 | FROM ubuntu:22.04 |
在启动容器时定义运行命令
1 | docker run helloworld:1.0 echo “Hello Docker” |
则会输出Hello Docker
并且不会输出Hello World
ENV
- 说明:在容器运行时通过修改环境变量达到相应运行效果
- 用法:
ENV <变量名>="变量值"
- 作用时机:构建镜像时
1 | FROM ubuntu:22.04 |
构建镜像后就可以通过改变环境变量来改变输出的值了
1 | docker run -e CONTENT=Docker helloworld:1.0 |
这样就会输出Docker
了
WORKDIR
- 说明:设置在容器中后的工作目录,若指定的路径未创建则会自动创建
- 用法:
WORKDIR <路径>
(路径可以是绝对路径也可以是相对路径) - 作用时机:构建镜像时
RUN
- 说明:在构建镜像时运行相应指令,与
CMD
差异在于作用时机不同 - 用法:
RUN <命令>
- 作用时机:构建镜像时
ADD
- 说明:将文件添加至镜像中,可以从本地路径添加,也可以从远端地址添加;如果是从本地文件中添加文件且若目标是tar、zip等压缩包则会自动解压
- 用法:
ADD <原路径> <镜像中目标路径>
- 作用时机:构建镜像时
EXPOSE
- 说明:声明暴露的端口(即使不声明,在启动容器时映射了相关端口也能正常访问)
- 用法:
EXPOSE <端口>/tcp
或EXPOSE <端口>/udp
(在不声明的情况下默认是tcp)
COPY
- 说明:类似于ADD,但只能从本地加载资源,并且不会自动解压压缩包
- 用法:
COPY <本地路径> <目标路径>
ENTRYPOINT
- 说明:类似于CMD,但是在启动容器时并不会被覆盖
- 用法:
ENTRYPOINT [“<命令>”,“<参数1>”,“<参数2>”,...]
(命令和参数作为json数组的元素去书写)或ENTRYPOINT <命令> <参数1> <参数2> ...
- 作用时机:容器启动时
可以和CMD配合使用,以达到启动命令只有部分能被覆盖
1 | ENTRYPOINT java -jar |
这样容器启动时就会默认运行java -jar app1.jar
1 | docker run java_test:1.0 app2.jar |
这样运行的就是java -jar app2.jar`
将镜像推送到镜像仓库
有时间我们自定义的镜像需要在多台设备上使用,这时我们就可以将构建的镜像推送到Docker Hub的镜像仓库中,需要在其他机器上部署时只需要pull下来即可
- 注册Docker Hub账号,这个在网页端进行,https://hub.docker.com
- 登陆账户:
docker login
,然后输入账户密码 - 构建镜像:
docker build -t <镜像名>:<标签> -f <DockerFile文件> <DockerFile路径>
- 给镜像打标签:
docker tag <镜像名>:<标签> <DockerHub用户名>/<镜像名>:<镜像标签>
,这一步其实是修改镜像标签,让其符合DockerHub个人镜像规范 - 推送镜像:
docker push <DockerHub用户名>/<镜像名>:<镜像标签>
DockerCompose
一般一个项目会有前端后端数据库等多个容器组成,并且要管理起网络、端口、数据卷和端口等信息,如果使用docker run
一个一个启动容器也是可以的,但是启动起来本不是特别方便,因此可以使用docker compose一键部署多个容器
安装
当前版本的docker已经自带了DockerCompose,并不需要单独安装,并且命令已经由docker-compose
变更为docker compose
,可以通过下面命令查看版本
1 | docker compose version |
快速入门
编写docker-compose.yaml
1 | services: |
运行
1 | docker compose up -d |
这样两个容器就在后台运行了
停止
1 | docker compose down |
模版文件书写
基本元素
- image:指定镜像
- environment:指定环境变量
- ports:指定发布端口
- volumes:指定数据卷
- command:覆盖容器启动后的默认指令
- restart:指定重启策略
- networks:指定docker网络
模版
其实看得懂DockerCompose就好,对着写几次就会了,这里提供一个有前后端服务的模版模版
DockerRun
先看看docker run
1 | #Docker网络 |
DockerCompose
1 | #version: "3.8" |
- 感谢您的赞赏。