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 create centos --name ***  // 不行就跳过这个create的环节直接用run(docker run -itd --name 别名 centos) 

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 -f $(docker ps -aq)

 强制删除所有镜像:

  docker rmi -f $(docker images -qa)

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 push时报错:docker denied: requested access to the resource is denied

解决办法

  1. 检查是否登录, docker login,  在root目录下的.docker目录下存在了config.json文件的话则表示登录成功,且里面保存了token信息包含用户名和密码的校验
  2. 检查image的tag名是否合法, 需要包含Repository的名字, docker tag image_name repository_name/image_name    举例:docker tag docker.io/mysql docker.io/2322062349/wangyaocong:20200909
  3. 此时再push就可以了, docker push repository_name/image_name  举例:docker push docker.io/2322062349/wangyaocong:20200909
  4. docker.io是必加的,如果仓库是docker的远程仓库的话,2322062349/wangyaocong则是仓库名,20200909是版本号
  5.  

     

     

     

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

制作镜像

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

通过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

其中的docker-compose用于定义和运行多容器的Docker应用程序,可以在yml文件中定义一个服务所涉及的多个docker服务,通过操作yml配置文件来一次性启动和配置docker集群服务
posted @ 2020-09-09 17:01  whhhd  阅读(457)  评论(0编辑  收藏  举报