文章目录
一、为什么要用Docker
- 容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker对系统资源的利用率更高,因此相比于传统的虚拟机技术,一个相同配置的主机能够运行更多数量的应用。
- Docker容器应用由于直接运行在宿主内核,无需启动完整的操作系统,因此有更快的启动时间。
- Docker的镜像提供了除内核外完整的运行时环境,确保了应用运行环境的一致性。
- 实现一次创建或配置,可以在任意地方正常运行,使用
Dockerfile
使镜像构建透明化; - Docker确保了执行环境的一致性,使得应用的迁移更容易。
- Docker使用的分层存储以及镜像的技术,使得应用重复部分的服用更为容易,方便应用的维护和扩展。
二、基本概念
镜像
Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会改变。
Linux的内核启动后,会挂载
root
文件系统为其提供用户空间支持,而Docker镜像就相当于一个root
文件系统,比如官方镜像ubuntu:18.04
就包含完整的一套Ubuntu18.04最小系统的root
文件系统。
Docker设计时,充分利用Union FS
技术,将镜像设计为分层存储的架构,所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
容器
容器和镜像的关系就像是面向对象程序设计中的对象与类的关系一样,镜像是静态的定义,容器是镜像运行时的实体。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。因此容器可以拥有自己的 root
文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。
每个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,可称这个为容器运行时读写而准备的存储层为容器存储层。
按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录],在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。
仓库
Docker Registry是一个集中的存储、分发镜像的服务。
一个Docker Registry包含多个仓库(Repository),每个仓库可以包含多个标签(Tag),每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签>
的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest
作为默认标签。
三、镜像加速
可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://knr0kbp8.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
运行docker info
命令即可看到相应的配置说明此时镜像加速成功。
四、Docker常用命令
帮助命令
docker version # 显示docker的版本信息
docker info # 显示docker的系统信息,包括镜像和容器的数量
docker command --help # 帮助命令
镜像命令
- docker images
- docker search
- docker pull
- docker rmi
docker images
查看所有本地的主机上的镜像:
root@ubuntu:/home/luo# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx alpine 6f715d38cfe0 8 weeks ago 22.1MB
hello-world latest bf756fb1ae65 9 months ago 13.3kB
# 解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的id
CREATED 镜像的创建时间
SIZE 镜像的大小
# 可选项
--all, -a 显示所有镜像
--quiet, -q 只显示镜像id
docker search
搜索镜像:
可选项:
--filter, -f 基于给定的条件对输出进行过滤
docker search --filter stars=3 busybox 搜索stars数量大于3的镜像
docker search --filter is-automated=true busybox 搜索自动化镜像
docker search --filter is-official=true --filter stars=3 busybox 搜索官方镜像
docker pull
下载镜像:
# 下载镜像 docker pull 镜像名[:tag]
root@ubuntu:/home/luo# docker pull mysql
Using default tag: latest # 如果不写tag,默认就是latest
latest: Pulling from library/mysql
d121f8d1c412: Pull complete # 分层下载,docker image的核心:联合文件系统
f3cebc0b4691: Pull complete
1862755a0b37: Pull complete
489b44f3dbb4: Pull complete
690874f836db: Pull complete
baa8be383ffb: Pull complete
55356608b4ac: Pull complete
dd35ceccb6eb: Pull complete
429b35712b19: Pull complete
162d8291095c: Pull complete
5e500ef7181b: Pull complete
af7528e958b6: Pull complete
Digest: sha256:e1bfe11693ed2052cb3b4e5fa356c65381129e87e38551c6cd6ec532ebe0e808 # 签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址
# 二者等价
docker pull mysql
docker pull docker.io/library/mysql:latest
查看Docker Hub上mysql镜像拉取所支持的标签,进而指定标签拉取镜像。
root@ubuntu:/home/luo# docker pull mysql:5.7
5.7: Pulling from library/mysql
d121f8d1c412: Already exists
f3cebc0b4691: Already exists
1862755a0b37: Already exists
489b44f3dbb4: Already exists
690874f836db: Already exists
baa8be383ffb: Already exists
55356608b4ac: Already exists
277d8f888368: Pull complete
21f2da6feb67: Pull complete
2c98f818bcb9: Pull complete
031b0a770162: Pull complete
Digest: sha256:14fd47ec8724954b63d1a236d2299b8da25c9bbb8eacc739bb88038d82da4919
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
docker rmi
根据容器id删除镜像,-f
选项用于强制删除镜像:
docker rmi -f 容器id # 删除指定的镜像
docker rmi -f 容器id 容器id 容器id # 删除多个容器镜像
docker rmi -f $(docker images -aq) # 删除全部的容器镜像
容器命令
说明:有了镜像之后才可以创建容器,在这里我们通过centos镜像来测试学习。
- docker run
- docker ps
- docker rm
- docker start/stop/restart/kill
首先拉取centos
镜像:
docker run
新建容器并启动。
root@ubuntu:/home/luo# docker run --help
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
# 参数说明
--name="Name" 为容器指定名字,例如tomcat01、tomcat02来区分容器
--detach, -d 后台方式运行容器
-it 使用交互方式运行,进入容器查看内容
-p 指定容器端口, -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口(常用)
-p 容器端口
容器端口
-P 随机指定端口
# 测试,启动并进入容器
root@ubuntu:/home/luo# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 0d120b6ccaa8 2 months ago 215MB
root@ubuntu:/home/luo# docker run -it centos /bin/bash
[root@4ea95e7ee45f /]# ls # 查看容器内的centos,基础版本,许多命令并不完善
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
# 从容器中退出主机
[root@4ea95e7ee45f /]# exit
exit
root@ubuntu:/home/luo# ls
demo Documents examples.desktop linux-4.15.tar.gz node-bulletin-board Public Templates xdp-tutorial
Desktop Downloads go Music Pictures sockmap Videos
退出容器使用exit
命令是直接停止容器并退出,可使用快捷键ctrl+P+Q
从而在容器不停止的情况下退出。
docker ps
列出所有运行的容器:
root@ubuntu:/home/luo# docker ps --help
Usage: docker ps [OPTIONS]
List containers
# 不加任何选项默认只显示当前正运行的容器
Options:
-a, --all # 列出当前正在运行的容器和历史运行过的容器
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print containers using a Go template
-n, --last int # 显示最近创建的n个容器
-q, --quiet # 只显示容器的编号
# 运行效果
root@ubuntu:/home/luo# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@ubuntu:/home/luo# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4ea95e7ee45f centos "/bin/bash" 14 minutes ago Exited (0) 14 minutes ago zen_edison
704c4795b10c centos "/bin/bash" 20 minutes ago Exited (13) 19 minutes ago
docker rm
删除容器
docker rm 容器id # 删除指定的容器,不能删除正在运行的容器,如果要强制删除 rm -f
docker rm -f $(docker ps -aq) # 删除所有的容器
docker ps -aq|xargs docker rm # 删除所有的容器
docker start/restart/stop/kill
启动 重启 停止 强制停止容器的操作
docker start 容器id # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止当前正在运行的容器
docker kill 容器id # 强制停止当前容器
常用其他命令
后台启动容器
# 命令 docker run -d 镜像名
常见的坑:docker容器使用后台运行,就必须有一个前台进程,docker发现前台没有应用,就会自动停止。nginx
容器启动后,发现自己没有提供服务,也会立刻停止。
查看日志
docker logs
# 选项
--follow, -f # 跟踪容器日志的最新更新
--timestamps,-t # 显示时间戳
--tail num(default all) # 从日志尾部开始展示的日志的条数
# 显示日志
# 通过shell脚本在centos bash中循环打印iie字符串
root@ubuntu:/home/luo# docker run -d centos /bin/sh -c "while true;do echo iie;sleep 1; done"
b449e7455e6e8cbcdf3ca8df661cfd6ac921465ff93296eb25097869ebbe3160
root@ubuntu:/home/luo# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b449e7455e6e centos "/bin/sh -c 'while t…" 4 seconds ago Up 3 seconds angry_wozniak
root@ubuntu:/home/luo# docker logs -tf --tail 10 b449e7455e6e
2020-10-11T08:32:24.591396088Z iie
2020-10-11T08:32:25.593913720Z iie
2020-10-11T08:32:26.595235908Z iie
2020-10-11T08:32:27.600110698Z iie
2020-10-11T08:32:28.603608767Z iie
2020-10-11T08:32:29.607475099Z iie
2020-10-11T08:32:30.612909623Z iie
2020-10-11T08:32:31.615959954Z iie
2020-10-11T08:32:32.620009950Z iie
2020-10-11T08:32:33.623083108Z iie
2020-10-11T08:32:34.630690386Z iie
2020-10-11T08:32:35.633210432Z iie
查看容器中的进程信息
# 命令 docker top 容器id
root@ubuntu:/home/luo# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b449e7455e6e centos "/bin/sh -c 'while t…" 5 minutes ago Up 5 minutes angry_wozniak
root@ubuntu:/home/luo# docker top b449e7455e6e
UID PID PPID C STIME TTY TIME CMD
root 100008 99984 0 01:32 ? 00:00:00 /bin/sh -c while true;do echo iie;sleep 1; done
root 100407 100008 0 01:37 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
查看镜像的元数据
docker inspect 容器id
进入当前正在运行的容器
# 通常容器都是使用后台方式运行的,需要进入容器,修改一些配置
# 第一种命令
docker exec -it 容器id /bin/bash
# 测试
root@ubuntu:/home/luo# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b449e7455e6e centos "/bin/sh -c 'while t…" 16 minutes ago Up 16 minutes angry_wozniak
root@ubuntu:/home/luo# docker exec -it b449e7455e6e /bin/bash
[root@b449e7455e6e /]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 11884 2880 ? Ss 08:32 0:00 /bin/sh -c while true;do echo iie;sleep 1; done
root 1028 1.0 0.1 12016 3328 pts/0 Ss 08:49 0:00 /bin/bash
root 1042 0.0 0.0 23024 1284 ? S 08:49 0:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /
root 1043 0.0 0.1 44592 3412 pts/0 R+ 08:49 0:00 ps aux
# 第二种命令
docker attach 容器id
# 测试
root@ubuntu:/home/luo# docker attach b449e7455e6e
正在执行当前代码...
# docker exec # 进入容器后开启一个新的终端
# docker attach # 进入容器正在执行的终端,不会启动新的进程
容器内文件拷贝到主机目录
docker cp 容器id:源文件路径 主机目的文件路径
docker cp 容器id:源文件路径 目的文件路径
# 测试
root@ubuntu:/home/luo# docker exec -it b449e7455e6e /bin/bash
[root@b449e7455e6e /]# pwd
/
[root@b449e7455e6e /]# more main.go # 查看文件中新建的go文件内容
package main
import "fmt"
func main(){
fmt.Println("Hello World!")
}
[root@b449e7455e6e /]# exit
exit
root@ubuntu:/home/luo# docker cp b449e7455e6e:/main.go /home/luo
root@ubuntu:/home/luo# more main.go
package main
import "fmt"
func main(){
fmt.Println("Hello World!")
}
一些实践
配置nginx
root@ubuntu:/home/luo# docker run -d --name nginx01 -p 8086:80 nginx
e8c4b4e392cce366505e7b3c63a7d3dabcccd37b4e9336ff0adb7f4de65e8dfd
root@ubuntu:/home/luo# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e8c4b4e392cc nginx "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 0.0.0.0:8086->80/tcp nginx01
root@ubuntu:/home/luo# curl localhost:8086
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
在主机端访问主机ip以及8086端口也能够显示对应的html
页面:
当继续执行docker stop e8c4b4e392cc
之后停止容器,此时再次刷新页面显示无法访问网站。
配置tomcat
# 拉取镜像
docker pull tomcat
# 运行容器
docker run -d -p 8888:8080 --name tomcat01 tomcat
# 测试访问没有问题
# 进入容器
docker exec -it tomcat01/ /bin/bash
# 发现问题:Linux命令少了,没有webapps(从webapps.dist拷贝过来);阿里云镜像默认是最小的镜像,保证最小可运行的环境,所有不必要的都会被剔除掉。
主机访问结果:
commit镜像
docker commit 提交容器成为一个新的副本
# 命令和git原理类似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]
五、总结
通过上面的学习,基本上掌握了docker的基本用法,同时对镜像分层的原理所有理解,个人感觉刚上手一项技术的时候还是看视频快点,看书或者官方文档容易抓不住重点,在对技术有了初步地了解之后再去针对性地查阅书籍或者文档往往会事半功倍(小伙伴们可以分享一下自己的学习方式哟)。以上就是Docker的入门知识了,下篇博文将会分享关于Docker数据卷、Dockerfile以及容器网络的内容,敬请期待!