docker的简介
docker是什么?
Docker 是一个开源的应用容器引擎, 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上。通俗点说就是把应用打包放到一个盒子(容器)里,然后运行这些盒子,这些盒子就是一个一个进程。
docker容器技术如何实现?
前面说了docker就是把应用放到一个盒子里,应用还是我们的应用不用关心,我们最关心的就是这个盒子怎么实现的。其实也很简单就是加一些挡板把这些线程都隔离起来类似我们一个个隔离起来的工位。
docker容器的本质就是宿主机上的一个进程,只不过是利用了 Linux 内核的cgroup,namespace,chroot等技术对进程进行封装隔离。实现了类似虚拟化的功能。(这些技术我们之后再讲)
docker与虚拟化的区别是什么?
HostOS:宿主机操作系统
Hypervisor:虚拟层,虚拟出硬件
Guest OS:虚拟机操作系统
VM在虚拟层上安装完全独立的Guest OS,在里面运行各种个样的程序。每个虚拟化应用程序不仅包括应用程序(可能只有50 MB)、必要的二进制文件和库,还包括整个客户操作系统(可能有10 GB),你可以在windows上运行linux操作系统。
Docker在Docker Engine层上面运行各种程序,利用的Host OS,Docker Engine容器仅包含应用程序及其依赖项。它在主机操作系统的用户空间中作为独立进程运行。
docker有哪些优势?
提高系统资源的利用率
快速的启动时间
开发,测试,生产环境一致
快速部署,迁移
docker基本概念和使用
镜像(image)
Docker镜像是由文件系统叠加而成,最底端是一个文件引导系统,第一层即bootfs。第二层是root文件系统rootfs(列如我们要构建一个mysql的镜像,那个这个镜像就包含了mysql的所有文件),这些文件就是一个只读的模板。利用这个模版可以用来创建 Docker 容器。
容器(Container)
Docker 利用容器来运行应用。 容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是 相互隔离的、保证安全的平台。 可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。 *注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。
docker仓库
仓库是集中存放镜像文件的场所。 仓库分为公开仓库(Public)和私有仓库(Private)两种形式。 最大的公开仓库是Docker Hub,存放了数量庞大的镜像供用户下载。 国内的公开仓库包括 Docker Pool 等,可以提供大陆用户更稳定快速的访问。 当然,用户也可以在本地网络内创建一个私有仓库。 当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓 库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来 就可以了。
理解了这三个概念,就理解了 Docker 的整个生命周期。
镜像
镜像拉取
docker pull [options] name [:tag] 表示从仓库拉取镜像 options是参数 name要拉取的镜像名tag是版本
我们这里拉取一下mysql的镜像
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker pull mysql:5.7.25
5.7.25: Pulling from library/mysql
27833a3ba0a5: Pull complete
864c283b3c4b: Pull complete
cea281b2278b: Pull complete
8f856c14f5af: Pull complete
9c4f38c23b6f: Pull complete
1b810e1751b3: Pull complete
5479aaef3d30: Pull complete
1d924ec3d520: Pull complete
1ab7ae63ac60: Pull complete
08aa5f3680e9: Pull complete
a832d0a0972a: Pull complete
Digest: sha256:dba5fed182e64064b688ccd22b2f9cad4ee88608c82f8cff21e17bab8da72b81
Status: Downloaded newer image for mysql:5.7.25
docker.io/library/mysql:5.7.25
需要特别说明的是,docker的镜像是分层的,这里每一行代表镜像的一层最后堆积成mysql的镜像。这种分层镜像的思想可以让底层的镜像得到复用。如果官网下载镜像特别慢可以使用阿里云进行加速具体可以参考https://blog.csdn.net/weixin_43569697/article/details/89279225
查看所有镜像
docker images会展示本地有的所有的镜像
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 62f1d3402b78 2 weeks ago 104MB
ubuntu latest d70eaf7277ea 3 weeks ago 72.9MB
mysql 5.7.25 98455b9624a9 20 months ago 372MB
ubuntu 12.10 3e314f95dcac 6 years ago 172MB
删除镜像
docker rmi 删除镜像
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker rmi 62f1d3402b78
Untagged: redis:latest
Untagged: redis@sha256:a0494b60a0bc6de161d26dc2d2f9d2f1c5435e86a9e5d48862a161131affa6bd
Deleted: sha256:62f1d3402b787aebcd74aaca5df9d5fe5e8fe4c0706d148a963c70d74a497e51
Deleted: sha256:a00918a3a63fe7820ab3b038f0c157d579e37cb53cb6627ff399a59b6b993d5b
Deleted: sha256:8b8d9955ce888edc9bb9fcbeac7e5bc02db761ee9cbf35e2d6d6c5e13d6efb91
Deleted: sha256:4767a65a353899f079e51c19590715802ab8fca0951166ec4966ed6bac48464e
Deleted: sha256:a8f09c4919857128b1466cc26381de0f9d39a94171534f63859a662d50c396ca
Deleted: sha256:2ae5fa95c0fce5ef33fbb87a7e2f49f2a56064566a37a83b97d3f668c10b43d6
Deleted: sha256:d0fe97fa8b8cefdffcef1d62b65aba51a6c87b6679628a2b50fc6a7a579f764c
创建镜像
创建镜像有两种方式一种是使用dockerfile编写,一种是使用docker commit让运行的容器变成镜像
DockerFile
我们用Dockerfile创建一个镜像,在mysql5.7.25的文件的基础上新建一个文件并且输入一句话
#mydocker file
#FROM表示以mysql:5.7.21镜像为基础镜像
FROM mysql:5.7.25
#执行命令在mysql根目录下创建一个文件dockerFirst.txt并写入内容dockerfile创建的镜像
RUN echo 'dockerfile创建的镜像' > /dockerFileFirst.txt
这个是我们写好的dockerfile运行一下试试注意最后的 . 一定不要省略表示在当前位置读取dockerfile也可以自己指定dockerfile的位置
[root@iZ2zehx0enix3hhxj0tiloZ mydockerfile]# docker build -t mysqldockerfile:v2.0 .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM mysql:5.7.25
---> 98455b9624a9
Step 2/2 : RUN echo 'dockerfile创建的镜像' > /dockerFileFirst.txt
---> Running in 8b17d4cbd312
Removing intermediate container 8b17d4cbd312
---> 0e4ef1f45616
Successfully built 0e4ef1f45616
#查看本地的镜像
[root@iZ2zehx0enix3hhxj0tiloZ mydockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysqldockerfile v2.0 0e4ef1f45616 34 seconds ago 372MB
mysqlfile v1.0 068db9de31ad 34 minutes ago 372MB
ubuntu latest d70eaf7277ea 3 weeks ago 72.9MB
mysql latest db2b37ec6181 3 weeks ago 545MB
mysql 5.7.25 98455b9624a9 20 months ago 372MB
ubuntu 12.10 3e314f95dcac 6 years ago 172MB
发现打的镜像已经存在了
关于dockerfile命令介绍
Docker commit
#启动刚才下载的mysql
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker run -p 3306:3306 --name mysql01 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.25
644ebae23f8f2a9c44b523b68fbb8c5fbb4adceb2152bb4cbd2bdd58ba29837a
#进入容器
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker exec -it mysql01 /bin/bash
root@644ebae23f8f:/# ls
bin boot dev docker-entrypoint-initdb.d entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
#创建一个文件并输入内容
root@644ebae23f8f:/# echo 'mysql test' > mysqlTest01.txt
#查看已经创建了该文件
root@644ebae23f8f:/# ls
bin boot dev docker-entrypoint-initdb.d entrypoint.sh etc home lib lib64 media mnt mysqlTest01.txt opt proc root run sbin srv sys tmp usr var
commit命令说明
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
OPTIONS说明:
-a :提交的镜像作者;
-c :使用Dockerfile指令来创建镜像;
-m :提交时的说明文字;
-p :在commit时,将容器暂停。
查看启动的容器
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
644ebae23f8f mysql:5.7.25 "docker-entrypoint.s…" 11 minutes ago Up 11 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp mysql01
构建镜像
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker commit -a fangfangbixia -m 'my first mysql' 644ebae23f8f mysqlfile:v1.0
sha256:068db9de31ad21099f86ecc446029ca17ef141df93014dc2bcde2ef663dce4ea
看到本地已有镜像,发现已经有了之前创建的镜像
#可以看到本地已经有fang
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysqlfile v1.0 068db9de31ad 2 minutes ago 372MB
ubuntu latest d70eaf7277ea 3 weeks ago 72.9MB
mysql 5.7.25 98455b9624a9 20 months ago 372MB
ubuntu 12.10 3e314f95dcac 6 years ago 172MB
上传镜像
用户可以通过 docker push 命令,把自己创建的镜像上传到仓库中来共享。例如,用户在 Docker Hub上完成注册后,可以推送自己的镜像到仓库中。如果不加地址和端口,那就是上传到Docker Hub。要传到自己的镜像仓库,必须包含地址,没有的话先tag。
docker tag [username]/xxx:tag来打tag
#先打个tag
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker tag mysql:5.7.25 fangfangbixia/mysql02
#上传镜像
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker push fangfangbixia/mysql02
The push refers to repository [docker.io/fangfangbixia/mysql02]
82582edf9553: Layer already exists
9209148debed: Mounted from library/mysql
364557e875f1: Layer already exists
5075b9328698: Pushed
97874ea0e7f9: Layer already exists
458d25c646d8: Layer already exists
ec41e34b35a0: Layer already exists
3437f67a712b: Layer already exists
0aa7d65147ef: Layer already exists
f411d8bde01c: Layer already exists
5dacd731af1b: Mounted from library/mysql
latest: digest: sha256:e889999df625a5a358a03cc433057cb5a8d3de17fbe11a70964da0eb9c7677b1 size: 2621
Docker 会上传镜像的每一层。因为fangfangbixia/mysql02 这个镜像实际上跟官方的 mysql 镜像一模一样,Docker Hub 上已经有了全部的镜像层,所以真正上传的数据很少,可以看到很多层都显示 Layer already exists
登录 https://hub.docker.com可以看到我们自己上传的镜像
删除所有镜像
docker rmi $(docker ps -a | awk '{print $1}')
容器
容器就是宿主机上的一个进程,这个进程独立运行着一个或一组应用
启动容器
docker run 创建一个新的容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
OPTIONS说明:
-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
-d: 后台运行容器,并返回容器ID;
-i: 以交互模式运行容器,通常与 -t 同时使用;
-P: 随机端口映射,容器内部端口随机映射到主机的端口
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
--name="nginx-lb": 为容器指定一个名称;
--dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
--dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-h "mars": 指定容器的hostname;
-e username="ritchie": 设置环境变量;
--env-file=[]: 从指定文件读入环境变量;
--cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;
-m :设置容器使用内存最大值;
--net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
--link=[]: 添加链接到另一个容器;
--expose=[]: 开放一个端口或一组端口;
--volume , -v: 绑定一个卷
需要注意的是我们可以使用 -it 以交互的模式启动容器,也可以使用-d 后台运行的模式启动容器启用一个mysql,设置名字为fangfangmysql01密码123456
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker run --name fangfangmysql01 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.25
展示所有容器
docker ps 展示所有运行中的容器
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85bc5e4d591f mysql:5.7.25 "docker-entrypoint.s…" 2 days ago Up 2 days 0.0.0.0:3306->3306/tcp, 33060/tcp fangfangmysql01
docker ps 会展示所有正在运行的容器,docker ps -a 展示所有的容器包括已经停止的容器
进入容器
docker exec 在运行的容器中执行命令,可以在运行的容器中直接指定bash
目录进入终端,进入到之前运行的终端中
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker exec -it fangfangmysql01 /bin/bash
root@1e2e25e1aebb:/#
退出容器
通过bash命令进入容器后,可以通过exit命令直接退出容器
root@1e2e25e1aebb:/# exit
exit
停止容器
docker stop 来停止一个运行中的容器。
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker stop fangfangmysql01
fangfangmysql01
当Docker容器中指定的应用终结时,容器也自动停止。 例如对于上一章节中只启动了一个终端
的容器,用户通过 exit 命令或 Ctrl+d 来退出终端时, 所创建的容器立刻停止。
启动停止容器
docker start 启动一个或者是多个处于停止中的容器
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker start fangfangmysql01
fangfangmysql01
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e2e25e1aebb mysql:5.7.25 "docker-entrypoint.s…" 18 minutes ago Up 4 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp fangfangmysql01
[root@iZ2zehx0enix3hhxj0tiloZ ~]#
可以看到启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。
删除容器
docker rm 删除容器
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker rm fangfangmysql01
fangfangmysql01
需要注意的是docker rm是删除容器,docker rmi是删除镜像
查看容器/镜像的详细信息
docker inspect < id> 或者是< name:tags>,docker中可以通过name+tags来确定唯一的镜像,查看镜像或者是容器的详细信息
[root@iZ2zehx0enix3hhxj0tiloZ ~]# docker inspect 98455b9624a9
[
{
"Id": "sha256:98455b9624a96e32b353297bb312913b6bbd62ac195cea2c7dd477209ba572d6",
"RepoTags": [
"mysql:5.7.25"
],
"RepoDigests": [
"mysql@sha256:dba5fed182e64064b688ccd22b2f9cad4ee88608c82f8cff21e17bab8da72b81"
],
"Parent": "",
"Comment": "",
"Created": "2019-03-26T23:42:41.544289046Z",
"Container": "7df6fb5998bd5716ae9608678f1b80b96f4de5cd427cf5ceed4993650ed447c6",
"ContainerConfig": {
"Hostname": "7df6fb5998bd",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {},
"33060/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.7",
"MYSQL_MAJOR=5.7",
"MYSQL_VERSION=5.7.25-1debian9"
]
。。。
到这里我们关于docker的镜像和容器已经学完了那么我们来思考一个问题,docker的多个容器是可以共享同一个镜像docker是怎么做到的?当某个容器修改了基础镜像的内容,这时其他容器 是否也会被修改?
嘿嘿还记得前面提到的镜像的分层吗?在docker中镜像是一层一层的,低层文件如果相同就共用。这种分层最大的一个好处就是 - 共享资源,相同的镜像只需要一份就可以了,所以我们在写dockerfile的时候尽量把共用的镜像写在下面,但是修改怎么办呢?会不会互相影响,答案是不会的。
当容器启动时,一个新的可写层被加载到镜像的顶部,这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中,只有容器层是可写的,容器层下面的所有镜像层都是只读的。这就是容器的 Copy-on-Write 特性。
Docker 支持不同的存储驱动,包括 aufs、devicemapper、overlay2、zfs 和 vfs 等等,在最新的 Docker 中,overlay2 取代了 aufs 成为了推荐的存储驱动。我们可以通过docker inspec查看容器的基本信息。
可以看到我这个容器用的是overlay2存储驱动,对overlay2来说UpperDir下的文件是可以写的。LowerDir文件夹下都是只读的。
容器网络
默认Docker的网络就是使用的bridge,一般内部地址都是172.x.x.x。假设我们启动一个mysql容器,在
主机上,我们可以通过内部地址访问,我们用docker inspect能看到它的ip地址
ping一下是可以ping通的。
但是172.x这个地址,对于其他机器来说是不可访问的。需要怎么办呢?要做端口映射。我们可以在容器启动的时候-p指定端口映射,用-P可以随机映射端口。然后直接访问宿主机的这个端口就可以了。
用navicat连接一下发现是可以连接通的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XwOAuF3k-1606141325513)(/Users/mac/Desktop/截屏2020-11-22 下午1.20.18.png)]
Docker数据卷
数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
数据卷可以在容器之间共享和重用
对数据卷的修改会立马生效
对数据卷的更新,不会影响镜像
数据卷默认会一直存在,即使容器被删除
注意:数据卷的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的数据卷。
一般像日志,数据库的数据我们都希望长期保存不会随着容器的删除而删除就需要把容器的目录挂载到宿主机上
在磁盘上创建一个文件夹,用来存放mysql的文件。比如 /data/mysql/data
docker run --name fangfangmysql02 -p 3306:3306 -v /data/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.25
9ab284b19d8aee1c04551ec077659ad59342ee359174c54c80552b6bc9160c59
安装ps:
apt-get update && apt-get install procps
安装ip:
apt-get update & apt-get install -y iproute2