小白学习docker只要这篇文章就够了(建议收藏)


docker是什么?


docker
🐳
作为容器化技术的代言人。
由于应用程序的运行被隔离在了一个独立的运行环境之中,这个独立的运行环境就好似一个容器,包裹住了应用程序,这就是容器技术名字的由来。
而docker相比于虚拟机有几个特点:

  • 启动速度快

  • 更轻量

docker内部组件

Namespace  
命名空间,提供一种对进程隔离的一种机制,例如进程,网络、挂载等资源

ControlGroups  
资源控制组的作用就是控制计算机资源的,与namespace不同CGroups 主要做的是硬件资源的隔离

Union File System  
联合文件系统,支持将不同位置的目录挂载到同一个虚拟文件系统,形成一种分层的模型

docker的核心组成


在docker体系中,有四个不得不介绍的,它们分别是:

镜像 ( Image )

容器 ( Container )
仓库(Registry)

镜像

镜像是一个特殊的文件系统,可以理解为一个只读包,甚至可以理解为类与实例中的类。
每个镜像可能有多个镜像组成。
它是一种层级结构,每次对镜像的修改,docker都会铸造成一个镜像层。

容器

容器可以理解为类与实例中的实例,镜像是死的是不可变的。
而容器却是一个活的空间。
每次启动容器都是通过镜像启动一个新的容器。


仓库

远端中的镜像仓库,例如npm仓库

安装docker


在安装 docker 之前,我们先来了解一下docker的版本定义,这有利于我们在之后的开发中选择和使用合适的 Docker 版本。
对于docker来说,它分为两个系列:

  • 社区版(ce)

  • 企业版(ee)

社区版和企业版的区别无非就是企业版收费,提供额外的服务。

                              
 sudo yum install yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo
https://download.docker.com/linux/centos/docker-ce.repo
 sudo yum install docker-ce
不出意外的话 输入docker -v出现图下页面就代表成功了


docker的运行过程

docker的运行过程可以简单的理解为,从远端仓库中拉取合适的镜像到本地–>通过镜像创建容器–>启动容器

使用docker


docker search (查看远端库的镜像)


npm search
类似,用来查看远端中的镜像,例如:

docker search ubuntu

会出现如上图,他有几个参数:

NAME 镜像名字

DESCRIPION

描述

STARS

星星数量

OFFICIAL

是否官方版本

AUTOMATED

是否是自制的

docker pull (拉取镜像)


从远端仓库中拉取镜像到本地,这里以
centos
镜像为例

docker pull centos

等到拉取成功后会出现下图所示:




当你不指定任何标签的时候,docker会默认拉取最新的tag,指定拉取

+ tag

例如
:
docker pull centos:7

每一个镜像都是由一组64位长度的hash码组成,这种组成的方式保证了全球的唯一性。

docker images(查看镜像)


从远端拉取镜像成功后我们可以通过docker images 来列出本地所有的镜像

docker images


如图下所示:

这边的image id 为12位和上方说的64位长度并不冲突,只是官方为了显示在控制台上好看一些。
将后方的位数省略了。

docker create (创建容器)

如果说镜像是个类,那么我们需要创建一个实例来让我们操作。


docker create centos

来创建一个centos的容器,创建成功后会生成一个64位的hash值,如图下:


如果当你本地没有centos的镜像时候,会默认从远端仓库中的拉取对应的版本。
我们还可以通过

–name
来指定容器的别名

docker ps (查看容器)


通过docker ps可以查看当前所有正在运行的容器,但是由于上方容器没有运行,在执行操作时,需要在后面加一个
-a
参数。
代表所有容器。

docker ps -a

docker start  stop  reset(启动/停止/重启容器)

通过 
docker create
创建的容器,是处于 Created 状态的,其内部的应用程序还没有启动,所以我们需要通过
 
docker start
 
命令来启动它。

docker start 8c784b9b2118


通过
docker start + 容器id 
来启动容器,如果给容器配置了别名,也可以通过别名来启动容器。
启动容器后通过

docker ps


如图下所示:


你会发现空空如也。
这是为什么呢,执行

docker ps -a



你会发现容器处于
Exited
状态。
这是因为如果容器内部没有进程正在运行,那么容器在

start
之后会停止。
如果存在进程的容器,例如nginx,mysql,你在启动后就会变成up状态。

docker run (创建并启动容器)

docker run
命令是
docker create
命令和
docker start
命令的合成,可是说是我们最常用的命令之一。
docker run 命令有很多参数,这里我例举一些常用的参数

– d 

后台运行容器,并返回容器ID
– i 以交互模式运行容器,通常与 -t 同时使用;
– p

端口映射,格式为:

主机(宿主)端口:容器端口
– t

为容器重新分配一个伪输入终端,通常与 -i 同时使用
– v

绑定数据卷

–name 为容器指定一个名称
–net 指定容器的网络连接类型

举个例子

docker run -p 80:80 -v nginx-html:/usr/share/nginx/html -d --name nginx nginx:latest
使用镜像 nginx:latest,以后台模式启动一个容器,将容器的 80 端口映射到主机的 80 端口,将容器的/usr/share/nginx/html目录映射到主机目录下的docker中的nginx-html数据卷中


并取名为nginx。

可以看到容器的状态变成了up。

每个docker容器和我们宿主机之间存在隔离关系,假设有一个nginx服务,内部容器监听的端口号是80,这时候如何将外面访问宿主机80端口号的时候,能够访问到nginx服务呢?
所以

我们需要作出映射通过
-p
将宿主机上的80端口和
nginx
端口
进行映射


-v
将宿主机中的目录挂载到容器的目录中
,便于以后数据的备份
和防止容器删除后数据的丢失。
网络和数据卷会在后文有专门提到。

docker exec   (在运行的容器中执行命令)

很多时间,我们需要的操作并不仅仅是按镜像所给出的命令启动容器而已,我们还会希望进一步了解容器或操作容器,这时候最佳的方式就是让我们进入到容器了。

这里以上方nginx容器为例。

docker exec -it nginx bash


你会发现前缀变成一串容器的hash了,说明你已经成功进入的容器内部。
这里我是以bash的方式进去,当然你也可以以其他的交互方式进入。

-it
命令和上方的
docker run
中参数一样,在run中
代表着创建一个新的容器并启动并进入容器内部


docker rmi? (删除容器或者镜像)

docker rm 容器id
docker rmi 镜像id


需要注意的是,如果容器正在运行中,需要先将容器停止后方能删除。

docker inspect (获取容器/镜像的元数据)

docker inspect [容器id/镜像id]


通过上述命令可以获取容器或者镜像的相关信息,如图

包含端口号映射情况,数据卷挂载情况,网络情况等,反正只要想看容器或者镜像的具体信息时候,敲这个命令准没错。

docker save load (导出镜像/导入镜像)

将容器导出成一个tar文件
-o
 
指定为指定文件中。

docker save -o nginx.tar [镜像id]

导入镜像

docker load -i nginx.tar

docker export import (导出容器/导入容器)

将容器导出成一个tar文件 

docker export -o nginx.tar [容器id]

导入容器,这里需要注意的是,使用
 
docker import
 
并非直接将容器导入,而是将容器运行时的内容以镜像的形式导入。
所以导入的结果其实是一个镜像,而不是容器。

docker import nginx.tar

docker cp (用于容器与主机之间的数据拷贝)

在主机目录下创建一个abc.txt文件

将目录下的abc.txt文件移到容器中的/data目录下

docker cp ./abc.txt a175b4a2fd94:/data

进入容器内部

docker exec -it a175b4a2fd94 bash

会发现/data目录下存在了abc.txt文件,反之,容器内容的文件或者目录也可以复制到主机内,只要将两者调换顺序即可

docker cp  a175b4a2fd94:/data /data/

其他命令

docker logs

获取容器的日志

docker port

查看容器映射端口情况

docker volume ls列出当前已经创建的数据卷

docker history

查看镜像的创建历史

docker diff

检查容器里文件结构的更改

docker kill

杀掉一个运行中的容器

docker login 

登陆远端镜像仓库

docker push

将本地镜像上传到远端仓库

可以去捣鼓捣鼓看看,把命令都敲个遍,玩不下去就删容器,删镜像。


制作镜像


当公共仓库中的镜像不能满足我们的需求时,或者对镜像进行个性化的定制时,我们需要制定出自己的镜像,方面以后经常性的使用。

通过docker commit制作镜像

假设我现在在nginx镜像构建出的一个容器中新建了一个abc.txt文件,那我如何在每次构建nginx镜像时都有这个abc.txt文。
这时直接将这个容器制作成镜像就可以解决。
具体命令如下

docker commit -m'我的nginx' -a'yalewan' a175b4a2fd94 mynginx:1.0


效果如下图所示

执行docker im
ages,你会发现多出来了一个镜像

-m 镜像提交的信息

-a

提交镜像的作者

-p

在commit时,将容器暂停。

通过Dockerfile制作镜像

Dockerfile 是 Docker 中用于定义镜像自动化构建流程的配置文件,能够明确的给定 Docker 镜像的制作过程。
假设这边我们以一个node项目为例(项目在宿主机中的nodeapp目录中,基于koa2中的项目

)如图:


  • 编写dockerfile


dockerfile具有以下几个参数

FROM

继承的镜像文件

COPY

拷贝数据

WORKDIR

工作路径

RUN

编译打包阶段运行命令

EXPOSE

暴露的端口号

CMD

容器运行阶段的命令

在nodeapp目录同级新建一个dockerfile文件,没有后缀名

FROM node                    # 基于node镜像
COPY ./nodeapp /nodeapp # 将nodeapp目录下d的文件移到容器中
WORKDIR /nodeapp # 工作目录nodeapp,类似移到nodeapp目录中
RUN npm install # 安装依赖
EXPOSE 3000 # 因为容器是隔离的,所以需要暴露端口

新建完成后大家可以看一下我现在的目录结构,

在home目录下执

docker build -t nodeapp .

-t
表示镜像的名字,不要忘记后面的
.
,dockerfile文件的相对路径,
.
表示在当前目录下。
运行结果如下

等到安装完毕后,查看镜像,会发现多出一个nodeapp的镜像

创建并启动容器,同时进入到容器内部,容器中已经存在了我们的node项目

docker run -p 3000:3000 -it nodeapp bash


npm start
启动nodeapp,并且浏览器访问


修改D
ocker
file 
在最后增加一句

CMD npm start


删除容器重新启动一遍,现在我们连启动的一步也省略了。
看到这边,相信你也对docker有了一定的认识,但相信我这仍然不是最佳选择,继续往下


数据卷


因为容器内部的文件系统是随着容器内部的生命周期所创建和移除的,并且容器隔离,我们很难从外部获得或者操作容器内部文件中的数据。
所以docker为了解决这个问题,提出了三种文件系统的挂载方式,分别为:

Bind Mount

Volume
和 
Tmpfs Mount

Volume

volumes 是docker管理宿主机文件系统的一部分,在
/var/lib/docker/volumes
目录
下,当你创建一个数据卷的时候,会默认放在
volumes
目录。
创建命令

docker volume create nginx-html


可以通过
docker volume ls
查看

通过
docker volume inspect nginx-html
来查看具体信息


我们来创建一个新的nginx容器来和数据卷进行挂载,命令如下图

docker run -d --name nginx -v nginx-html:/usr/share/nginx/html nginx

挂载成功后我们进入宿主机中


cd /var/lib/docker/volumes/nginx-html/_data

你会发现宿主机中的nginx-html目录中多了两个文件


同时我们进入到容器内部

docker exec -it 7454e37763d0 bash
cd /usr/share/nginx/html

你会发现容器内部的文件和挂载的那个目录文件是一样的,说明我们挂载成功了


当然,无论你在容器内部文件系统中,还是在挂载的docker volumes目录中增加或者修改文件,互相关联的另一个都会随之改变


Bind Mount

bind mount相对于volumn唯一的区别就是将容器内的目录映射到宿主机中的任意一个位置。

docker run -d -v /mnt:/mnt -name logs centos 


唯一区别的就是,volume对应的是文件名(nginx-html),而bindMount则是一个相对路径(/mnt)

Tmpfs Mount

Tmpfs Mount是临时挂载到系统内存中,存储不是永久的,会随着容器的停止而消失。
适用于不需要持久保存的数据。
挂载时需要用–tmpfs来指定。

docker run -d --name webapp --tmpfs /webapp/cache webapp:latest

网络


一个完整的项目可能存在很多容器,比如node,mysql,redis,webapp等,它们彼此之间可能存在通信问题,比如node容器如何连接mysql的服务等。
为此,docker提供了网络驱动。
常用的网络驱动有3种类型:

Bridge Driver

Host Driver

None Driver

可以通过
docker network ls
来查看网络驱动


如果想看网络驱动的具体信息和对应的容器,使用
docker network inspect [网络驱动]

docker network inspect bridge

如图下所示:

Bridge Driver

会在主机上创建一个虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。
如上图显示所示,bridge的ip地址都是以172.17开头显示。
不指定网络默认为bridge模式。

Host Driver

通过–net host来使用host模式,host模式是宿主机公用一个network,使用宿主机的IP和端口。

创建一个新的nginx3的容器,通过–net host来指定网络驱动

docker run -d --name nginx3 --network host nginx


启动完毕,进入到host详情,会发现多出了一个容器,并且没有ip地址,如图下:

None Driver

不为Docker容器进行任何网络配置。通过
–net none

创建自定义网络

docker network create -d bridge mynetwork

执行查看 
d
ocker network ls

容器之间的link

通常由于容器之前隔离,两个容器之间的网络是无法进行通信的,通常我们需要通过link来建立容器之间的连接。

docker run -d --name nodeapp --link mysql node

或者说两个容器同时加入自定义的网络中也是可行的

docker run -d --name mysql --network mynetwork mysql
docker run -d --name nodeapp --network mynetwork node 

docker-compose编排容器


往往一个完整的项目可能通过很多容器组成,为每个容器挂载网络,指定数据卷会变非常的麻烦,幸好docker-compose为我们解决了这个问题。
安装docker-compose。

sudo curl -L 
"https://github.com/docker/compose/releases/download
/1.24.0/docker-compose-$(uname -s)-$(uname -m)"

-o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose

下面我以nginx容器为例

version: "3"

networks:
my-network:
driver: bridge

services:              
nginx:
image: nginx
    container_name: nginx        
ports:
- 80:80
- 443:443
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./logs/nginx:/var/log/nginx
    restart: always   
networks:
- my-network

versi
on

版本
b
uild
从dockfile构建
image
从哪个镜像构建
por
ts
映射的端口号
depends_on
依赖

启动
顺序
volumes
挂载

数据
net
works
网络
restart

通过
docker-compose up
-d
启动容器 如果有重名的容器记得先删除哦!


你会发现容器已经创建完毕,当有很多个容器时,只要往下继续补充即可。
当然,容器编排技术不知docker-compose这一种,k8s也是一种不错的选则,这里就不在赘述了,有兴趣的话可以研究一下

tips

  • 如何镜像加速(从远端拉镜像国内会很慢)

 # /etc/docker/daemon.json
{
"registry-mirrors": [
"https://dockerhub.azk8s.cn",
"https://reg-mirror.qiniu.com"
]
}
# 找到 /etc/docker/daemon.json文件,添加上述文件
# 如果没有该文件,创建一个即可
sudo systemctl daemon-reload
# 重启服务
sudo systemctl restart docker

感谢大家


1.如果文章对你有帮助,请动动你的小手指点个赞👍吧,你的赞是我创作的动力。

2.关注公众号「前端精英」!

不定期推送高质量文章哦。


https://juejin.im/post/5e8c34326fb9a03c7a3316bf

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论