admin管理员组文章数量:1648973
容器介绍
容器其实是一种沙盒技术。沙盒就是能够像一个集装箱一样,把你的应用"装"起来的技术。这样,应用与应用之间,就因为有了边界而不至于相互干扰;(隔离性)
而被装进集装箱的应用,也可以被方便地搬来搬去。(移植性)
容器的本质到底是什么?
容器的本质是进程。(在宿主机上被隔离的进程)容器镜像就是这个wind系统里的".exe"安装包.
Docker介绍:
Docker是Docker.Inc公司开源的一个基于轻量级虚拟化技术的容器引擎项目,整个项目基于Go语言开发,并遵从Apache 2.0协议。Docker使得应用开发者和运维工程师可以以统一的方式跨平台发布应用,并且以几乎没有额外开销的情况下提供资源隔离的应用运行环境。 Docker 是一个开源工具,它可以让创建和管理 Linux 容器变得简单。容器就像是轻量级的虚拟机,并且可以以秒级的速度来启动或停止。 官网:docker https://hub.docker/ ---docker官方库--(存镜像)也叫docker-hub
没有容器的时候:
1.rd开发产品(需要配置开发环境)
2.测试(需要配置测试环境)
3.op上线(需要部署上线环境)
开发 测试 运维
有容器之后:
-
rd开发产品(开发过程中就做成镜像,在docker容器里配置环境)
-
测试(直接测试)
-
把容器打包成镜像交给运维,运维上线
Docker 优势
1、交付物标准化 Docker的标准化交付物称为"镜像",它包含了应用程序及其所依赖的运行环境,大大简化了应用交付的模式。 2、应用隔离 Docker可以隔离不同应用程序之间的相互影响,----容器之间相互独立互不影响。容器技术部署速度快,开发、测试更敏捷。通过内核的命名空间来实现的,将容器的进程、网络、消息、文件系统和主机名进行隔离。(当然磁盘、内存仍然没有隔离) 3、移植性:一次构建,多次交付 类似于集装箱的"一次装箱,多次运输",Docker镜像可以做到"一次构建,多次交付"。 Docker是利用容器来实现的一种轻量级的虚拟技术,从而在保证隔离性的同时达到节省资源的目的。Docker的可移植性可以让它一次建立,到处运行。Docker的度量可以从以下几个方面进行: 4、可度量性 Docker主要通过cgroups控制组来控制资源的度量和分配,提高系统利用率,降低资源成本. 5、轻量级:与传统的虚拟机相比,容器共享主机操作系统的内核,而不是携带一个完整的操作系统副本。这意味着容器启动速度非常快,资源消耗也相对较少。
容器技术主要依赖于操作系统提供的功能,特别是Linux内核中的以下特性:
-
命名空间(Namespaces):为容器提供隔离的视图,使得每个容器看起来像是在自己的系统中运行。
-
控制组(Control Groups, cgroups):用来限制、记录和隔离容器使用的物理资源(CPU、内存、磁盘I/O等)。
容器和 VM 的主要区别
1.表面区别: 容器占用体积小,虚拟机占用体积大 隔离性:虚拟机隔离性好,容器的隔离性差。容器提供了基于进程的隔离,而虚拟机提供了资源的完全隔离,虚拟机比容器安全. 启动速度:虚拟机可能需要一分钟来启动,而容器只需要一秒钟或更短。 容器共享宿主机操作系统的内核,而虚拟机使用独立的内核。Docker 的局限性之一是,它只能用在64位的操作系统上。 2.本质区别: 容器是隔离的进程,共享宿主机操作系统内核,启动速度快,占用资源少; 虚拟机是完整的虚拟计算机,具有较好的隔离性,但需要较长的启动时间和较大的资源占用。
常见的容器技术
- Docker:目前最流行的容器平台之一,提供了一整套工具和服务来构建、部署和管理容器化应用程序。
- Kubernetes(K8s):一个开源平台,用于自动化容器化应用的部署、扩展和管理。
- LXC (Linux Containers):一个更底层的技术,直接使用Linux内核特性来创建和管理容器。
docker安装
CentOS 7 中 Docker 的安装:
Docker 软件包已经包括在默认的 CentOS-Extras 软件源(联网使用centos7u2自带网络Yum源)里。因此想要安装 docker,只需要运行下面的 yum 命令:
# yum install -y epel*
# yum install docker
启动 Docker 服务:
# service docker start
# chkconfig docker on
CentOS 7
# systemctl start docker.service
# systemctl enable docker.service
确定docker服务在运行:结果会显示服务端和客户端的版本,如果只显示客户端版本说明服务没有启动
# docker version
Client:
Version: 1.13.1
API version: 1.26
...
Server:
Version: 1.13.1
API version: 1.26 (minimum version 1.12)
···
docker版本与官方安装方式
moby、docker-ce与docker-ee
最早时docker是一个开源项目,主要由docker公司维护。2017年3月1日起,docker公司将原先的docker项目改名为moby,并创建了docker-ce和docker-ee。
三者关系:
moby是继承了原先的docker的项目,是社区维护的的开源项目,谁都可以在moby的基础打造自己的容器产品 docker-ce是docker公司维护的开源项目,是一个基于moby项目的免费的容器产品 docker-ee是docker公司维护的闭源产品,是docker公司的商业产品
moby project由社区维护,docker-ce project是docker公司维护,docker-ee是闭源的docker公司维护。
CentOS--官方安装
如果是centos,上面的安装命令会在系统上添加yum源:/etc/yum.repos.d/docker-ce.repo
# wget https://download.docker/linux/centos/docker-ce.repo
# mv docker-ce.repo /etc/yum.repos.d/
# yum install -y docker-ce
或者直接下载rpm安装
# wget https://download.docker/linux/centos/7/x86_64/stable/Packages/docker-ce-17.09.0.ce-1.el7.centos.x86_64.rpm
# yum localinstall docker-ce-17.09.0.ce-1.el7.centos.x86_64.rpm
国内源安装新版docker
使用aliyun docker yum源安装新版docker
删除已安装的Docker
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
配置阿里云Docker Yum源
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun/docker-ce/linux/centos/docker-ce.repo
列出所有可用的 Docker 软件包版本
用于安装或更新 Docker
yum list docker-ce --showduplicates
安装Docker新版本
制定版本,比如Docker 18.03.0,加上rpm包名的版本号部分或不加都可以
# 安装最新版本
yum install -y docker-ce
# 安装制定版本
yum install docker-ce-18.03.0.ce -y
启动Docker服务
systemctl enable docker
systemctl start docker
查看Docker版本和当前版本状态
# 检查 Docker 客户端的版本
docker -v
# 提供详细的客户端和服务端版本信息
docker version
查看Docker运行状态
docker info
报错1:
docker info的时候报如下错误:bridge-nf-call-iptables is disabled
解决1:
追加如下配置,然后重启系统
# vim /etc/sysctl.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-arptables = 1
问题2:
虚拟机ping百度也能ping通,但是需要等好几秒才出结果,关键是下载镜像一直报错如下
# docker pull daocloud.io/library/nginx
Using default tag: latest
Error response from daemon: Get https://daocloud.io/v2/: dial tcp: lookup daocloud.io on 192.168.1.2:53: read udp 192.168.1.189:41335->192.168.1.2:53: i/o timeout
解决2:
我的虚拟机用的网关和dns都是虚拟机自己的.1或者.2,把DNS改成8.8.8.8问题就解决了,ping百度也秒出结果
# vim /etc/resolv.conf
nameserver 8.8.8.8
简单测试
运行一个容器
# docker run -itd daocloud.io/library/ubuntu #放后台运行
# docker run -it daocloud.io/library/ubuntu /bin/bash #下载并运行容器
(/bin/bash、/bin/sh都是登录shell,/bin/bash有环境变量)
Unable to find image 'daocloud.io/library/ubuntu:latest' locally
latest: Pulling from library/ubuntu
5c939e3a4d10: Pull complete
c63719cdbe7a: Pull complete
19a861ea6baf: Pull complete
651c9d2d6c4f: Pull complete
Digest: sha256:bc025862c3e8ec4a8754ea4756e33da6c41cba38330d7e324abd25c8e0b93300
Status: Downloaded newer image for daocloud.io/library/ubuntu:latest
如果自动进入下面的容器环境,说明•ubuntu镜像运行成功,Docker的安装也没有问题:可以操作容器了
root@db8e84e2ea96:/#
国内镜像源
去查看如何使用aliyun的docker镜像库
Docker 加速器
使用 Docker 的时候,需要经常从官方获取镜像,但是由于显而易见的网络原因,拉取镜像的过程非常耗时,严重影响使用 Docker 的体验。因此 DaoCloud 推出了加速器工具解决这个难题,通过智能路由和缓存机制,极大提升了国内网络访问 Docker Hub 的速度。 Docker 加速器对 Docker 的版本有要求吗? 需要 Docker 1.8 或更高版本才能使用。 Docker 加速器支持什么系统? Linux, MacOS 以及 Windows 平台。 Docker 加速器是否收费? 提供永久免费的加速器服务,请放心使用。
国内比较好的镜像源:aliyun和daocloud
daocloud.io--官网
配置道客的镜像
进入网站:DaoCloud 道客 – 云原生领域的创新领导者/
注册帐号:soso666
进入镜像市场
随便选择一个,选择mysql
上面有详细的使用命令。但是每个镜像的命令不一样,在选择一个:
[root@docker-server ~]# docker pull daocloud.io/library/nginx #下载镜像
Using default tag: latest
latest: Pulling from library/nginx
0a4690c5d889: Pull complete
9719afee3eb7: Pull complete
44446b456159: Pull complete
Digest: sha256:f83b2ffd963ac911f9e638184c8d580cc1f3139d5c8c33c87c3fb90aebdebf76
Status: Downloaded newer image for daocloud.io/library/nginx:latest
daocloud.io/library/nginx:latest
配置阿里云的镜像仓库
创建阿里云的私有仓库
使用自己的私有仓库
登录:
[root@docker-server ~]# docker login --username=aliyun1308451786 crpi-bi3swcirbp9a2x5x-hangzhou.personal.cr.aliyuncs
Password: Yunjisuan666@
...
Login Succeeded
重新打标记
[root@yixuan ~]# docker tag daocloud.io/library/nginx:latest registry-shanghai.aliyuncs/testpm/nginx:1.18
上传到自己的仓库
[root@yixuan ~]# docker push registry-shanghai.aliyuncs/testpm/nginx:1.18
查看上传的镜像
自己的nginx:1.1版本已经上传成功!
使用自己的仓库
配置加速器
配置阿里加速器:
如果这个目录/etc/docker/不存在就创建
[root@yixuan ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://br003st4.mirror.aliyuncs"]
}
[root@yixuan ~]# systemctl daemon-reload
[root@yixuan ~]# systemctl restart docker
配置华为云的加速器
配置阿里加速器:
如果这个目录/etc/docker/不存在就创建
[root@yixuan ~]# vim /etc/docker/daemon.json
{
..... ,
"registry-mirrors": [ "https://ac54865dcd3145a48ee9dc347ed733c0.mirror.swr.myhuaweicloud" ]
}
[root@yixuan ~]# systemctl daemon-reload
[root@yixuan ~]# systemctl restart docker
docker基本概念
Docker系统
Docker系统有两个程序:docker服务端和docker客户端
docker服务端:是一个服务进程,管理着所有的容器。也叫docker engine。
docker客户端:扮演着docker服务端的远程控制器,可以用来控制docker的服务端进程。
大部分情况下,docker服务端和客户端运行在一台机器上
Docker三大核心组件
Docker 镜像 - Docker images
Docker 仓库 - Docker registeries
Docker 容器 - Docker containers
容器的三大组成要素
(1)名称空间 (Namespace) 容器隔离(pid,net,mnt,user,)
- 功能:提供进程、网络、文件系统等方面的隔离。
- 类型:
- PID 命名空间:隔离进程 ID。
- 网络命名空间:隔离网络设备、IP 地址。
- 挂载命名空间:隔离文件系统挂载点。
- 用户命名空间:隔离用户 ID 和组 ID。
- UTS 命名空间:隔离主机名和域名。
- IPC 命名空间:隔离进程间通信资源。
(2)控制组(资源限制)(Control Groups, cgroups)
- 功能:限制和记录容器使用的物理资源。
- 资源类型:
- CPU:限制 CPU 使用率。
- 内存:限制内存使用量。
- 磁盘 I/O:限制读写速率。
(3)文件系统(UnionFS,如 OverlayFS)(镜像分层)
- 功能:支持镜像分层存储和高效管理。
- 特点:
- 分层:容器镜像由多个只读层加上一个可写层组成。
- 快照:创建容器文件系统的快照。
- 节省空间:多个容器共享只读层,写时复制。
docker 仓库:用来保存镜像,可以理解为代码控制中的代码仓库。同样的,Docker 仓库也有公有和私有的概念。这些镜像可以是自己创建,或者在别人的镜像基础上创建。
docker 国内仓库
ali
网易蜂巢
daocloud
=========================
docker公有仓库
docker.io -------docker官方库也叫docker-hub
类似于github一样,面向全球的一个docker镜像的公共仓库。如果在国内使用速度太慢。
===============================
docker私有仓库
个人或者公司部署的非公开库
阿里、harbor、腾讯、华为
docker镜像命名解析
Docker 镜像是 Docker 容器运行时的只读模板,每一个镜像由一系列的层组成。Docker 使用 UnionFS 来将这些层联合到单独的镜像中。当你改变了一个 Docker 镜像,比如升级到某个程序到新的版本,一个新的层会被创建。
在 Docker 的术语里,一个只读层被称为镜像,一个镜像是永久不会变的。由于镜像不可写,所以镜像是无状态的。
镜像是Docker最核心的技术之一,也是应用发布的标准格式。那么docker镜像是如何命名的,这也是Docker里面比较容易令人混淆的一块概念:Registry,Repository, Tag and Image。
那么Registry又是什么呢?Registry存储镜像数据,并且提供拉取和上传镜像的功能。Registry中镜像是通过Repository来组织的,而每个Repository又包含了若干个Image。下面是在本地机器运行docker images的输出结果:
常说的"ubuntu"镜像其实不是一个镜像名称,而是代表了一个名为ubuntu的Repository,同时在这个Repository下面有一系列打了tag的Image,Image的标记是一个GUID,为了方便也可以通过Repository:tag来引用。
镜像由三部分组成:
镜像名称:仓库名称+镜像分类+tag名称(镜像版本)
1.存储对象:images
2.格式:库名/分类:tag
3.tag:表示镜像版本
镜像的大体分类方式:这不是规定
1.以操作系统名字
centos的docker镜像:
centos5
centos6
centos7
-----------------
2.以应用的名字
nginx的docker镜像
tomcat的docker镜像
mysql的docker镜像
镜像名字
完整镜像名称示例:
docker.io/library/nginx:v1
docker.io/library/nginx:latest
daocloud.io/library/nginx
镜像ID:
所有镜像都是通过一个 64 位十六进制字符串来标识的。 为简化使用,前 12 个字符可以组成一个短ID,一般我们看到的是12位的我们称之为短ID,只要我们每个ID号不冲突就可以了,可以在命令行中使用。
镜像本身:是由一层一层的镜像合在一起的,最底层的镜像我们称为基础镜像,在这个基础镜像的基础上还可以在做镜像,在做的镜像称为子镜像,对于子镜像来讲在谁的基础之上做的谁就是父镜像。 基础镜像:一个没有任何父镜像的镜像,谓之基础镜像。 centos7 镜像 centos7+nginx 镜像
Docker 容器
Docker 容器和文件夹很类似,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。Docker 容器可以运行、开始、停止、移动和删除。每一个 Docker 容器都是独立和安全的应用平台,Docker 容器是 Docker 的运行部分。
docker镜像和容器的区别
一、Docker镜像
要理解Docker镜像和docker容器之间的区别,确实不容易。。
一个Docker镜像可以构建于另一个Docker镜像之上,这种层叠关系可以是多层的。第1层的镜像层我们称之为基础镜像(Base Image),其他层的镜像(除了最顶层)我们称之为父层镜像(Parent Image)。这些镜像继承了他们的父层镜像的所有属性和设置。
Docker镜像通过镜像ID进行识别。镜像ID是一个64字符的十六进制的字符串。但是当我们运行镜像时,通常我们不会使用镜像ID来引用镜像,而是使用镜像名来引用。
镜像可以发布为不同的版本,这种机制我们称之为标签(Tag)。
二、Docker容器
Docker容器可以使用命令创建:
docker run -it imagename /bin/bash
它会在所有的镜像层之上增加一个可写层。这个可写层有运行在CPU上的进程,而且有两个不同的状态:运行态(Running)和退出态 (Exited)。这就是Docker容器。当我们使用docker run启动容器,Docker容器就进入运行态,当我们停止Docker容器时,它就进入退出态。
当我们有一个正在运行的Docker容器时,从运行态到停止态,我们对它所做的一切变更都会永久地写到容器的文件系统中。要切记,对容器的变更是写入到容器的文件系统的,而不是写入到Docker镜像中的。我们可以用同一个镜像启动多个Docker容器,这些容器启动后都是活动的,彼此还是相互隔离的。我们对其中一个容器所做的变更只会局限于那个容器本身。如果对容器的底层镜像进行修改,那么当前正在运行的容器是不受影响的,不会发生自动更新现象。
名字空间--namespace
namespace 名字空间隔离
cgroup 资源限制
名字空间是 Linux 内核一个强大的特性。每个容器都有自己单独的名字空间,运行在其中的应用都像是在独立的操作系统中运行一样。名字空间保证了容器之间彼此互不影响。
Docker名称空间分类
- pid 名字空间--进程的隔离。不同用户的进程就是通过 pid 名字空间隔离开的,且不同名字空间中可以有相同 pid。所有的 LXC 进程在 Docker中的父进程为Docker进程,每个 LXC 进程具有不同的名字空间。同时由于允许嵌套,因此可以很方便的实现嵌套的 Docker 容器。
- net 名字空间 ----做网络接口隔离的。有 了 pid 名字空间, 每个名字空间中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net 名字空间实现的, 每个 net 名字空间有独立的 网络设备, IP 地址, 路由表, /proc/net 目录。这样每个容器的网络就能隔离开来。
- ipc 名字空间。容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication - IPC), 包括信号、消息队列和共享内存、socket、管道等。
- mnt名字空间。专门处理每一个容器的目录,每一个容器里面都有相同的目录,这些名字都会重名。
- uts 名字空间。UTS("UNIX Time-sharing System") 名字空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非主机上的一个进程。--用来存放每一个容器的主机名和域名。
- user 名字空间。用来隔离每一个容器的用户和组的,你上面有,我上面也有。所以需要给他隔离。
面试题:
linux系统里面ipc通信有几种方式
socket套接字:网络进程间的通信
管道:本地进程间的通信:echo hello | grep e
信号: kill -9 PID 这种我们叫信号量级,也是本地进程间的通信
共享内存:每个操作系统里面共享内存多大,是物理内存的一半
消息队列
镜像管理
基础命令
搜索镜像
这种方法只能用于官方镜像库。搜索基于 centos 操作系统的镜像
docker search centos
按星级搜索镜像
查找 star 数至少为 100 的镜像:
docker search ubuntu -f stars=100
# -f:filter
拉取镜像
# docker pull centos
注:没有加registry,默认是从docker.io下载的
# docker pull daocloud.io/library/tomcat:7
# docker pull daocloud.io/library/centos:6
推送镜像
docker push [OPTIONS] NAME[:TAG|@DIGEST]
--disable-content-trust: 忽略镜像的校验,默认开启。
-a, --all-tags: 将镜像的所有标签推送到仓库。
-q, --quiet: 禁止冗长输出。
查看本地镜像
docker image list
或者
docker images
查看镜像详情
docker image inspect 镜像id
删除镜像
删除一个或多个,多个之间用空格隔开,可以使用镜像名称或id
docker rmi daocloud.io/library/mysql
或者
docker rmi 81debc
参数解释:
rm Remove one or more containers ---移除一个或多个容器
rmi Remove one or more images ---删除一个或多个镜像
强制删除:--force
如果镜像正在被使用中可以使用--force强制删除
# docker rmi docker.io/ubuntu:latest --force
-f, --force Force removal of the image
注意: 容器运行中不能删除,将容器停止后,删除容器在删除镜像。
只查看所有镜像的id:
docker images -q
# -q, --quiet
删除所有镜像:
docker rmi $(docker images -q)
查看镜像制作的过程
相当于dockfile
使用镜像名或者镜像ID都可以
docker history daocloud.io/library/nginx
容器管理
docker run语法
语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
OPTIONS:
-a, --attach=[]:指定要附加到容器的 STDIN/STDOUT/STDERR 流。
-c, --cpu-shares=[N]:CPU权重(相对于其他容器)。
-d, --detach:分离模式:在后台运行容器并打印容器 ID。
-e, --env=[]:设置环境变量。
--env-file=[]:从文件中读取环境变量。
-h, --hostname=[HOSTNAME]:容器的主机名。
-i, --interactive:保持 STDIN 打开,即使没有附加。
--init:运行 init 进程,如果容器内的进程不是 init 类型的。
-l, --label=[]:添加元数据到容器。
-m, --memory=[BYTES]:内存限制。
-n, --name=[NAME]:分配容器一个名称。
-p, --publish=[]:发布容器端口映射到宿主机。
-P, --publish-all:随机端口映射到宿主机上的所有公开端口。
--privileged:给容器更多的权限(危险)。
--read-only:以只读模式运行容器。
-t, --tty:分配一个伪 tty。
-u, --user=[USER]:设置用户或 UID(格式:[USER][:GID])。
-v, --volume=[]:绑定挂载目录。
--volume-driver=[]:指定卷驱动程序的名称。
--workdir=[PATH]:工作目录。
基础命令
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
OPTIONS说明
OPTIONS说明(常用):有些是一个减号,有些是两个减号
--name= :"容器新名字" 为容器指定一个名称;
-d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
也即启动交互式容器(前台有伪终端,等待交互);
-P: 随机端口映射,大写P
-p: 指定端口映射,小写p
创建新容器但不启动
docker create -it daocloud.io/library/centos:5 /bin/bash
创建运行容器
同一个镜像可以启动多个容器,每次执行run子命令都会运行一个全新的容器
docker run -itd --restart=always daocloud.io/library/centos:7 /bin/bash
#最常用
-i:标准输入输出,以交互模式运行容器
-t:分配一个伪输入终端或控制台
--restart=always:容器随docker engine自启动,因为在重启docker的时候默认容器都会被关闭
也适用于create选项
-d 后台运行容器,并返回容器ID;
-e标志用于设置环境变量
如果执行成功,说明CentOS 容器已经被启动,并且应该已经得到了 bash 提示符。
--rm:默认情况下,每个容器在退出时是可以保存容器所产生的数据。但是当你仅仅需要短暂
的运行一个容器用于测试,并且这些数据不需要保存,当你退出容器之后,这个容器就不用了。
这个时候就需要--rm参数了。
注意:--rm 和 -d不能共用
容器名称
启动容器时,可以使用--name参数为容器分配一个自定义的名字。
如果不指定--name参数,Docker会自动为容器分配一个随机的名称。
# docker run -it --name 名字 daocloud.io/centos:6 /bin/bash #名字自定义
# docker run -it --name tomcat_1 50fc2d0 /bin/bash #不加-d,exit会关闭容器
# 一般不加/bin/bash,就需要加-d。这时exit退出,容器不会关闭
# docker run -itd --name tomcat_2 50fc2d0
如果你在执行docker run时没有指定--name,那么自动生成一个随机字符串UUID。这个UUID标识是由Docker deamon生成的。但是对于一个容器来说有个name会非常方便,当你需要连接其它容器时或者类似需要区分其它容器时,使用容器名称可以简化操作。无论容器运行在前台或者后台,这个名字都是有效的。
rename ---修改容器名称
# docker rename命令来修改容器的名称
docker rename old_name new_name
[root@yixuan ~]# docker rename mytest testmy
[root@yixuan ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
774c02898fb1 daocloud.io/library/nginx "/bin/bash -c 'while…" 5 minutes ago Up About a minute 80/tcp testmy
stats
断开连接并关闭容器
exit
断开连接而不关闭容器
快捷键:ctrl+p+q
查看容器
语法:docker ps [options]
[options]
-a 列出当前所有正在运行的容器+历史上运行过的
-l 显示最近创建的容器
-n 显示最近n个创建的容器
-q 静默模式,只显示容器编号
1. 列出运行状态的容器: # docker ps
2. -a 列出所有容器 # docker ps -a
3. 只查看所有容器id: # docker ps -a -q
查看容器详细信息
inspect :用于查看容器的配置信息,包含容器名、环境变量、运行命令、主机配置、网络配置和数据卷配置等。目标:查找某一个运行中容器的id,然后使用docker inspect命令查看容器的信息。提示:可以使用容器id的前面部分,不需要完整的id。
docker inspect 容器名/容器ID
启动容器
docker start name #容器ID也可以
这里的名字是状态里面NAMES列列出的名字,这种方式同样会让容器运行在后台
#启动所有容器
docker start $(docker ps -aq)
关闭容器
docker stop 容器ID或容器名
docker kill 容器ID或容器名 --强制终止容器
# 杀死所有running状态的容器
docker kill $(docker ps -q)
stop和kill的区别
docker stop命令给容器中的进程发送SIGTERM信号,默认行为是会导致容器退出,当然,
容器内程序可以捕获该信号并自行处理,例如可以选择忽略。而docker kill则是给容器的进程发送
SIGKILL信号,该信号将会使容器必然退出。
删除容器
docker stop <容器ID或名称> # 先停止容器
docker rm <容器ID或名称> # 再删除容器
docker rm -f <容器ID或名称> #强制删除正在运行的容器,慎用,会直接终止容器的运行。
#删除所有已退出的容器
docker rm $(docker ps -qf status=exited)
docker ps -a -q | xargs docker rm
暂停容器进程
pause :暂停容器中所有的进程
unpause:恢复容器内暂停的进程,与pause对应
[root@yixuan ~]# docker pause c7
[root@yixuan ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c0e0f43807d 98ebf73aba "/bin/bash" 7 minutes ago Up 7 minutes (Paused) 80/tcp c7
[root@yixuan ~]# docker unpause c7 #恢复
重启容器
docker restart name
让容器运行在后台
docker run -itd 镜像ID /bin/bash
-d后台运行必须要加-it
如果在docker run后面追加-d=true或者-d,那么容器将会运行在后台模式。此时所有I/O数据只能通过网络资源或者共享卷组来进行交互。因为容器不再监听你执行docker run的这个终端命令行窗口。但你可以通过执行docker attach来重新附着到该容器的会话中。
[root@yixuan ~]# docker attach 容器ID/容器名字
显示容器资源使用统计信息的实时流
docker stats
# 实时显示正在运行的容器的资源消耗情况,包括CPU使用率、内存使用量、网络I/O等。
连接容器(进入容器)
前提是容器在运行状态中
docker attach 命令用于附加到正在运行的容器的标准输入、输出和错误流。
前提是容器创建时必须指定了交互式shell。
docker attach 容器ID或名称可以将当前的终端连接到容器中,并与容器进行交互。
docker exec 命令用于在正在运行的容器中执行命令。有两种任务类型可以创建:
1. 交互型任务:
docker exec -it 容器ID或名称 /bin/bash
# 可以进入并与容器进行交互,并在容器中执行命令。
2. 后台型任务:
docker exec 容器ID或名称 命令 # 在容器中执行指定的命令
# 不会与容器进行交互,只是在容器内部执行命令。
监控容器的运行
可以使用logs、top、wait这些子命令
使用docker logs命令查看容器的运行日志
# docker logs [OPTIONS] CONTAINER Options:
--details 显示更多的信息
-f, --follow 跟踪实时日志
--since string 显示自某个timestamp之后的日志,或相对时间,如42m(即42分钟)
--tail string 从日志末尾显示多少行日志, 默认是all
-t, --timestamps 显示时间戳
--until string 显示自某个timestamp之前的日志,或相对时间,如42m(即42分钟)
1、查看最新日志
docker logs <容器ID/容器名>
查看docker容器日志可以使用容器的ID或者名称,选择其中一个即可
2、查看实时日志
docker logs -f <容器ID/容器名>
3、查看指定行数的日志
docker logs --tail 行数 <容器ID/容器名>
如果我们只想查看最新的200行日志,则可以使用下面命令
docker logs -f --tail=200 <容器ID/容器名>
[root@yj ~]# docker pull daocloud.io/library/nginx
[root@yj ~]# docker images
[root@yj ~]# docker run -it --name nginx1 98ebf73 /bin/bash
root@8459191dbe7c:/# /usr/sbin/nginx #启动nginx
ctrl+p+q --- 退出
[root@yj ~]# docker inspect nginx1 #找到ip地址
[root@yj ~]# curl -I http://172.17.0.3 #宿主机访问容器可以访问成功
HTTP/1.1 200 OK
Server: nginx/1.17.1
Date: Mon, 09 Mar 2020 14:49:40 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 25 Jun 2019 12:19:45 GMT
Connection: keep-alive
ETag: "5d121161-264"
Accept-Ranges: bytes
[root@yj ~]# curl -I http://172.17.0.3 #继续测试访问
在开启一个终端:
[root@yj ~]# docker logs -f nginx1 #动态查看容器日志
root@8459191dbe7c:/# /usr/sbin/nginx
root@8459191dbe7c:/# 172.17.0.1 - - [09/Mar/2020:14:49:33 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.29.0" "-"
172.17.0.1 - - [09/Mar/2020:14:49:40 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.29.0" "-"
# docker logs --tail=2 App_Conainer 查看倒数2行的容器日志
top:显示一个运行的容器里面的进程信息
[root@yixuan ~]# docker top nginx #容器ID也可以
wait :--捕捉容器停止时的退出码
执行此命令后,该命令会"hang"在当前终端,直到容器停止,此时,会打印出容器的退出码
在第一个终端执行停止容器命令
[root@yixuan ~]# docker stop nginx1
===============================
[root@yixuan ~]# docker wait 01d8aa #第二个终端操作
0
docker run 之后容器退出的状态码:
0,表示正常退出
非0,表示异常退出
宿主机和容器之间相互COPY文件
cp的用法如下:
docker cp CONTAINER:PATH LOCALPATH --从容器拷贝到本机
docker cp LOCALPATH CONTAINER:PATH --从本机拷贝到容器
如:容器nginx中/usr/local/bin/存在test.sh文件,可如下方式copy到宿主机
[root@yixuan ~]# docker exec -it nginx /bin/bash
root@2a9a18b4a485:/# cd /usr/local/bin/
root@2a9a18b4a485:/usr/local/bin# touch test.sh
ctrl+p+q 退出
[root@yixuan ~]# docker cp mytest:/usr/local/bin/test.sh /root/
修改完毕后,将该文件重新copy回容器
[root@yixuan ~]# ls
anaconda-ks.cfg test.sh
[root@yixuan ~]# echo "123" >> test.sh
[root@yixuan ~]# docker cp /root/test.sh mytest:/usr/local/bin/
docker容器镜像制作
一、容器文件系统打包
制作个人的镜像需要的步骤:
1.先有一个基础镜像,下载------>2.把镜像运行起来----->3.进入容器做你的修改-------4.将这个容器打包成一个新镜像。
将容器的文件系统打包成tar文件,也就是把正在运行的容器直接导出为tar包的镜像文件
docker export
命令可以将容器的内容导出为一个 tar 归档文件。这个命令只会导出容器的文件系统,不会保存容器的元数据(如镜像历史记录、元数据标签等)。
有两种方式:
在运行容器内导出为tar包,把容器做成镜像
[root@yixuan ~]# docker ps #运行一个容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
96e2b7265d93 daocloud.io/library/centos:6 "/bin/bash" About an hour ago Up About an hour c6
[root@yixuan ~]# docker exec -it c6 /bin/bash
[root@96e2b7265d93 /]# vi a.txt #编辑一个文件
123
[root@96e2b7265d93 /]# yum install -y vim wget #安装一个软件
[root@yixuan ~]# docker export -o centos6-1.tar 96e2b726 #容器ID
-o, --output
[root@yixuan ~]# ls #保存到当前目录下
anaconda-ks.cfg centos6-1.tar
在宿主机上将指定容器导出为镜像
[root@yixuan ~]# docker export 容器名称 > 镜像.tar
导入镜像归档文件到其他宿主机:
import
[root@yixuan ~]# docker import centos6-1.tar centos6-1:v1 # 自定义名字和版本
sha256:b8414448c913259a28d623643a7b67a6c13da9b3259e70ee5febb16c2b0b1095
[root@yixuan ~]# docker images
[root@yixuan ~]# docker run -it --name c6.1 centos6-1:v1 /bin/bash
[root@4a29d58d3bd2 /]# ls
a.txt bin dev etc home lib lib64 lost+found media mnt opt proc root sbin selinux srv sys tmp usr var
[root@4a29d58d3bd2 /]# cat a.txt
123123
二、通过容器创建本地镜像
背景:容器运行起来后,又在里面做了一些操作,并且要把操作结果保存到镜像里
方案:使用 docker commit 指令,把一个正在运行的容器,直接提交为一个镜像。
docker commit
命令可以将容器的状态保存为一个新的镜像,这个镜像包含了容器的文件系统和元数据。这种方式不仅导出了文件系统,还保留了容器的其他属性,如环境变量、启动命令等。
在容器内部新建了一个文件
[root@yj ~]# docker run -it --name c7 daocloud.io/library/centos:7 /bin/bash
[root@2e8f /]# touch test.txt
将这个新建的文件提交到镜像中保存
docker commit 2e8f soso/test:v2
也可以这样例子:
docker commit -m "my images version1" -a "soso" 108a85b1ed99 daocloud.io/ubuntu:v2
-m 添加注释
-a 作者
108a85b1ed99 容器环境id
daocloud.io/ubuntu:v2 镜像名称:hub的名称/镜像名称:tag
-p,–pause=true 提交时暂停容器运行
镜像迁移
保存一台宿主机上的镜像为tar文件,然后可以导入到其他的宿主机上:
save打包
将镜像打包,与下面的load命令相对应
语法:docker save -o xxx.tar 容器名
[root@yixuan ~]# docker save -o nginx.tar daocloud.io/library/nginx
load导入
与上面的save命令相对应,将上面sava命令打包的镜像通过load命令导入,(实验环境中原来机器上面有镜像可以先删除掉。)
语法:docker load < xxx.tar
[root@yj ~]# docker load < nginx.tar
[root@yj ~]# docker images
#把容器导出成tar包 export import
#把容器做成镜像 commit -a "" -m ""
#把镜像保存为tar包 save load
部署私有仓库应用
私有仓库镜像:
registry --官方出品, 没有图形界面.Docker hub官方已提供容器镜像registry,用于搭建私有仓库
拉取镜像
docker pull daocloud.io/library/registry:latest
docker images #查看拉取的镜像
#在daemon.json文件中添加私有镜像仓库地址
vim /etc/docker/daemon.json
{
"insecure-registries":["http://192.168.145.15:5000"], #添加,注意用逗号结尾
"registry-mirrors":["https://00ub0bmk.mirror.aliyuncs"]
}
#添加完记得重启
systemctl restart docker
#若重启docker,容器状态不全是up状态,可以执行docker-compose restart
systemctl status docker
目录映射
运行容器:会自动创建
docker run -d -v /home/dockerdata/registry:/var/lib/registry --name "pri_registry" --restart=always -p 5000:5000 daocloud.io/library/registry
参数解释:
/home/dockerdata/registry表示为宿主机的目录,如果不存在自动创建
-v 目录映射(容器卷) 宿主机的目录:容器目录
把宿主机的目录挂载到容器中,将数据目录挂载出来就是为了防止docker私有仓库这个容器
被删除的时候,仓库里面的镜像也被删除。
-p 端口映射:本地端口:容器端口 (容器端口固定,本地端口可以自定义)
注:如果创建容器不成功,报错防火墙,解决方案如下
#systemctl stop firewalld
#yum install iptaqbles*
#systemctl start iptables
#iptables -F
#systemctl restart docker
[root@yixuan ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0823df72b160 daocloud.io/library/registry "/entrypoint.sh /etc…" About a minute ago Up About a minute 0.0.0.0:5000->5000/tcp pri_registry
连接容器查看端口状态
[root@yj ~]# docker exec -it 0823df7 /bin/sh
# 注意这里未安装 bash,需要使用/bin/sh
/ # netstat -lntp #查看5000端口是否开启
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 :::5000 :::* LISTEN 1/registry
/ #
在本机查看能否访问该私有仓库, 看看状态码是不是200
[root@yixuan ~]# curl -I http://127.0.0.1:5000
HTTP/1.1 200 OK
给镜像打tag
下载1个比较小的镜像buysbox:
docker pull daocloud.io/library/busybox
上传前必须给镜像打tag 注明ip和端口:
docker tag daocloud.io/library/busybox 192.168.157.141:5000/busybox
下面这个Mysql是测试的第二个镜像,从daocloud拉取的:
docker pull daocloud.io/library/mysql
docker tag daocloud.io/library/mysql 192.168.157.141:5000/daocloud.io/library/mysql
docker images
注:tag后面可以使用镜像名称也可以使用id,我这里使用的镜像名称,如果使用官方的镜像,
不需要加前缀,但是daocloud.io的得加前缀。
客户端修改请求方式为http
默认为https,不改会报以下错误:
Get https://master.up:5000/v1/_ping: http: server gave HTTP response to HTTPS client
[root@yj ~]# vim /etc/docker/daemon.json #不存在则创建
{ "insecure-registries":["192.168.246.141:5000"] }
重启docker:
[root@yj ~]# systemctl daemon-reload
[root@yjn ~]# systemctl restart docker
上传镜像到私有仓库
[root@yj ~]# docker push 192.168.157.141:5000/busybox
[root@yj ~]# docker push 192.168.157.141:5000/daocloud.io/library/mysql
宿主机查看存放镜像目录
ls /home/dockerdata/registry/docker/registry/v2/repositories/
查看私有仓库里的所有镜像
语法: # curl http://ip:port/v2/repo名字/tags/list
~]# curl http://192.168.157.141:5000/v2/busybox/tags/list
{"name":"busybox","tags":["latest"]}
~]# curl http://192.168.157.141:5000/v2/daocloud.io/library/mysql/tags/list
{"name":"daocloud.io/library/mysql","tags":["latest"]}
这条命令会查看仓库下面所有的镜像:
~]# curl http://192.168.157.141:5000/v2/_catalog
{"repositories":["busybox","daocloud.io/library/mysql","mysql"]}
拉取镜像测试:
1.先将刚才打了tags的镜像删掉
[root@yj ~]# docker rmi 192.168.157.141:5000/busybox
2.拉取镜像:
[root@yj ~]# docker pull 192.168.157.141:5000/busybox
[root@yj ~]# docker images
部署docker web ui应用
下载并运行容器:
docker pull uifd/ui-for-docker #拉取
docker run -it -d --name docker-web -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock docker.io/uifd/ui-for-docker
# 如果本地有压缩包,可以本地上传
docker load < web-ui.tar
docker run -itd --name docker-web -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock 965940f98fa5
浏览器访问测试
http://192.168.157.141:9000/
容器管理
镜像下载
部署私有仓库harbor
[root@harbor ~]# wget https://storage.googleapis/harbor-releases/release-1.8.0/harbor-offline-installer-v1.8.0.tgz
下载docker-compose
[root@harbor ~]# curl -L https://github/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
或者本地上传
[root@harbor ~]# rz -y
[root@harbor ~]# cp docker-compose-Linux-x86_64 /usr/bin/docker-compose
[root@harbor ~]# chmod +x /usr/local/bin/docker-compose
http访问方式的配置:
[root@kub-k8s-master harbor]# vim harbor.yml #使用IP地址,需要修改的内容如下
hostname: 192.168.157.129 #改成自己的ip
解压harbor仓库
[root@harbor ~]# tar xf harbor-offline-installer-v1.8.0.tgz
[root@harbor ~]# vim load .sh
#!/bin/bash
cd /root/myharbor
for i in `ls /root/myharbor`
do
#echo $i
docker load < $i
done
[root@harbor ~]# sh load.sh
[root@kub-k8s-master ~]# cd harbor
[root@kub-k8s-master harbor]# ./install.sh #需要等待下载镜像
可以看到
docker-compose 使用
[root@harbor harbor]# docker-compose down #停止服务
[root@harbor harbor]# docker-compose up -d #放后台
浏览器访问测试:
http://192.168.157.129
然后在界面新建项目
客户端配置连接仓库地址
[root@docker-server ~]# vim /etc/docker/daemon.json
{
"insecure-registries": ["192.168.157.141"] #仓库的ip地址,配置http方式连接
}
[root@docker-server ~]# systemctl daemon-reload
[root@docker-server ~]# systemctl restart docker
[root@harbor harbor]#docker-compose up -d #启动harbor仓库
登陆仓库
#可以指定用户名
[root@docker-server ~]# docker login -u admin 192.168.157.129
#也可以不指定
[root@docker-server ~]# docker login 192.168.157.129
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker/engine/reference/commandline/login/#credentials-store
Login Succeeded
将生成的jspgou镜像上传到仓库中
[root@harbor harbor]# docker tag test/jspgou:1.1 192.168.157.129/pm-server/jspgou:1.1
[root@harbor harbor]# docker push 192.168.157.129/pm-server/jspgou:1.1
登陆仓库界面查看
Dockerfile创建镜像
Docker 提供了一种更便捷的方式,叫作 Dockerfile,Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
Dockerfile参数
# FROM 指令指定基础镜像,并且必须是Dockerfile中的第一条指令。
# 语法:
FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>
# 如果不以任何镜像为基础,可以写为:
FROM scratch
# 如果不指定<tag>或<digest>,默认值为latest。
# RUN 指令运行指定的命令。
# 语法:
RUN <command>
RUN ["executable", "param1", "param2"]
# 在Linux上默认使用/bin/sh -c,在Windows上默认使用cmd /S /C。
# 多行命令不要写多个RUN,因为每一个RUN指令都会创建一个新的镜像层,导致镜像臃肿。
# RUN书写时的换行符是\
# CMD 指令指定容器启动时要运行的命令。
# 语法:
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2
# 参数需要用双引号,不能用单引号,因为Docker解析的是一个JSON array。
# LABEL 指令为镜像指定标签。
# 语法:
LABEL <key>=<value>
LABEL <key>=<value> <key>=<value> ...
# 示例:
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \ that label-values can span multiple lines."
# 建议写成一行,如太长需要换行则使用\
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
# MAINTAINER 指令指定作者。
# 语法:
MAINTAINER <name>
# EXPOSE 指令暴露容器运行时的监听端口给外部。
# 语法:
EXPOSE <port>
EXPOSE <port>/<protocol>
# 注意:EXPOSE不会使容器直接访问主机的端口,如果需要映射端口,需在启动容器时使用-p参数。
# ENV 指令设置环境变量。
# 语法:
ENV <key> <value>
ENV <key>=<value> ...
# ADD 指令复制文件到镜像中。
# 语法:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
# <dest>路径可以是容器内的绝对路径,也可以是相对于工作目录的相对路径。
# <src>可以是一个本地文件、本地压缩文件或URL,如果是URL,ADD命令类似于wget。
# COPY 指令复制文件到镜像中。
# 语法:
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
# 与ADD的区别在于,COPY的<src>只能是本地文件。
# ENTRYPOINT 指令定义启动时的默认命令。
# 语法:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
# 注意:ENTRYPOINT可以被CMD指令的参数替换,但ENTRYPOINT定义的命令本身不会被替换。
docker build命令用于根据给定的Dockerfile构建Docker镜像。
1、docker build语法
docker build [OPTIONS] <PATH | URL | ->
1. 常用选项说明
--build-arg,设置构建时的变量
--no-cache,默认false。设置该选项,将不使用Build Cache构建镜像
--pull,默认false。设置该选项,总是尝试pull镜像的最新版本
--compress,默认false。设置该选项,将使用gzip压缩构建的上下文
--disable-content-trust,默认true。设置该选项,将对镜像进行验证
--file, -f,Dockerfile的完整路径,默认值为‘PATH/Dockerfile’
--isolation,默认--isolation="default",即Linux命名空间;其他还有process或hyperv
--label,为生成的镜像设置metadata
--squash,默认false。设置该选项,将新构建出的多个层压缩为一个新层,但是将无法在多个
镜像之间共享新层;设置该选项,实际上是创建了新image,同时保留原有image。
--tag, -t,镜像的名字及tag,通常name:tag或者name格式;可以在一次构建中为一个镜像设置多个tag
--network,默认default。设置该选项,Set the networking mode for the RUN instructions during build
--quiet, -q ,默认false。设置该选项,Suppress the build output and print image ID on success
--force-rm,默认false。设置该选项,总是删除掉中间环节的容器
--rm,默认--rm=true,即整个构建过程成功后删除中间环节的容器
示例:
docker build -t soso/nginx:v1 .
docker build 是docker创建镜像的命令
-t 是标识新建的镜像属于soso的nginx镜像
:v2.1 是tag
"." 默认读取当前目录的Dockerfile文件
如果其是名字,则用-f
docker build -t soso/nginx:v1 -f Dockerfile
2.创建过程
2.1 创建镜像所在的文件夹和Dockerfile文件
[root@yj ~]# mkdir sinatra
[root@yj ~]# cd sinatra/
[root@yj sinatra]# touch Dockerfile
2.2 Dockerfile文件中写入指令
每一条指令都会更新镜像的信息
[root@yj sinatra]# vim Dockerfile
FROM daocloud.io/library/centos:7
MAINTAINER soso soso@yixuan
RUN touch a.txt
RUN mkdir /test
格式说明:
指令要大写,"#"是注解。
每一个指令后面需要跟空格
FROM 命令是告诉docker 我们的镜像什么从哪里下载。一般选择比较小的系统镜像
MAINTAINER 是描述 镜像的创建人。
RUN 命令是在镜像内部执行的命令。
2.3 创建镜像
命令:注意此时在Dockerfile目录
[root@yj sinatra]# docker build -t soso/centos:7 .
docker build 是docker创建镜像的命令
打的tag一般就是私有仓库的地址和版本
.或者Dockerfile的目录
2.4 从镜像创建容器
docker ps -a # 查看镜像
docker run -it soso/centos:7 /bin/bash
Dockerfile容器化python的flask应用
用 Docker 部署一个用 Python 编写的 Web 应用
部署流程
基础镜像(python)-->flask-->部署python应用----->打包成镜像
web框架 flask django
代码功能
如果当前环境中有"NAME"这个环境变量,就把它打印在"Hello"后,否则就打印"Hello world",最后再打印出当前环境的 hostname。
[root@yj ~]# mkdir python_app
[root@yj ~]# cd python_app/
[root@yj python_ app]# vim app.py
from flask import Flask
import socket
import os
app = Flask(__name__)
@app.route('/')
def hello():
html = "<h3>Hello {name}!</h3>" \
"<b>Hostname:</b> {hostname}<br/>"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname())
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
应用依赖
定义在同目录下的 requirements.txt 文件里,内容如下:
[root@yj python_app]# vim requirements.txt
Flask
Dockerfile制作容器镜像
vim Dockerfile #创建Dockerfile,编辑以下内容
FROM daocloud.io/library/python:2.7-slim
WORKDIR /app
ADD . /app
RUN pip install --trusted-host pypi.python -r requirements.txt
EXPOSE 80
ENV NAME World
CMD ["python", "app.py"]
Dockerfile文件说明
FROM python:2.7-slim
# 使用官方提供的 Python 开发镜像作为基础镜像
# 指定"python:2.7-slim"这个官方维护的基础镜像,从而免去安装 Python 等语言环境的操作。
WORKDIR /app ---cd /app
# 将工作目录切换为 /app,意思是在这一句之后,Dockerfile 后面的操作都以这一句指定的
/app 目录作为当前目录。
ADD . /app
# 将当前目录下的所有内容复制到/app下. Dockerfile里的原语并不都是指对容器内部的操作。
比如 ADD,指的是把当前目录(即 Dockerfile 所在的目录)里的文件,复制到指定容器内的目录
当中。
ADD还支持使用TAR文件和URL路径,并且会将tar压缩文件(gzip, bzip2以及 xz格式)解压缩
COPY ./a.txt /app
RUN pip install --trusted-host pypi.python -r requirements.txt
# 使用 pip 命令安装这个应用所需要的依赖
EXPOSE 80 # 允许外界访问容器的 80 端口
ENV NAME World # 设置环境变量
VOLUME ["/data"]
# 定义匿名数据卷挂载点。通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,
而是自动生成的。需要通过inspect去查看对应宿主机上面的目录。
CMD ["python", "app.py"]
# CMD给出的是一个容器启动以后,默认的容器启动后的执行命令。这里命令为 python app.py
app.py的实际路径是 /app/app.py。CMD ["python", "app.py"]
等价于 "docker run python app.py"。
现在目录结构
[root@yj python_app]# ls
Dockerfile app.py requirements.txt
构建镜像
[root@yj python_app]# docker build -t 192.168.157.129/jdsc/py-app:v1 .
-t 给这个镜像加一个 Tag
Dockerfile 中的每个原语执行后,都会生成一个对应的镜像层。即使原语本身并没有明显地修改文件的操作(比如,ENV 原语),它对应的层也会存在。只不过在外界看来,这个层是空的。
查看结果
[root@yixuan python_app]# docker images
REPOSITORY TAG IMAGE ID ...
testpython latest 16bc21f3eea3
启动容器
[root@yj python_app]# docker run -itd --name mypy -p 82:80 192.168.157.129/jdsc/py-app:v1
-p 端口映射:本地端口:容器端口
查看容器
[root@yj python_app]# docker ps
CONTAINER ID IMAGE COMMAND CREATED
ce02568e64ce testpython "python app.py" About a minute ago
访问容器内应用
[root@yixuan ~]# curl http://localhost:4000
<h3>Hello World!</h3><b>Hostname:</b> f201f6855136<br/>
Dockerfile部署jenkins
[root@yj ~]# mkdir tomcat
[root@yj ~]# cd tomcat/
[root@yj tomcat]# vim Dockerfile
# This my first jenkins Dockerfile
# Version 1.0
FROM daocloud.io/library/centos:7
MAINTAINER yunjisuan
ENV JAVA_HOME /usr/local/jdk1.8.0_271
ENV PATH=$JAVA_HOME/bin:$PATH
ENV TOMCAT_HOME /usr/local/apache-tomcat-8.5.69
#老版本的配置方式:
#ENV PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
#ENV CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
ADD apache-tomcat-8.5.69.tar.gz /usr/local/
ADD jdk-8u271-linux-x64.tar.gz /usr/local/
RUN rm -rf /usr/local/apache-tomcat-8.5.69/webapps/*
ADD jenkins.war /usr/local/apache-tomcat-8.5.69/webapps
RUN rm -rf apache-tomcat-8.5.69.tar.gz apache-tomcat-8.5.69.tar.gz
EXPOSE 8080
ENTRYPOINT ["/usr/local/apache-tomcat-8.5.69/bin/catalina.sh","run"] #运行的命令
[root@yj tomcat]# pwd
/root/tomcat
[root@yj tomcat]# ls #将jdk与tomcat还有jenkins的包上传到tomcat目录中
apache-tomcat-8.5.69.tar.gz Dockerfile jdk-8u271-linux-x64.tar.gz jenkins.war
[root@yj tomcat]# docker build -t jenkins:v1 .
[root@yj tomcat]# docker run -itd --name jenkins1 -p 8081:8080 jenkins:v1
[root@yj tomcat]# netstat -lntp # 看到8081端口,说明启动成功
CMD与ENTRYPOINT的区别
一、dockerfile中的 CMD
1、每个dockerfile中只能有一个CMD,如果有多个那么只执行最后一个。
2、CMD 相当于启动docker时候后面添加的参数看,举个简单例子:
# docker run -itd --name test image(镜像) /bin/bash -c
a、镜像名称后面跟了一个/bin/bash -c ,其实等价于在dockerfile中的CMD ["/bin/bash","-c"]。
b、如果dockerfile中的CMD中有了CMD["/bin/bash","-c"],那么就不用在执行的时候再添加了,
如果添加了参数的话那么就相当于要执行你添加的参数,默认的CMD中的参数就无效了。
二、dockerfile中的ENTRYPOINT
1、一个dockerfile中ENTRYPOINT也只能存在一个,若存在多个那么只执行最后一个,你可以理解
为开机启动的意思,和CMD有点像,不过还是有区别。
2、举个简单例子:
a、dockerfile中有ENTRYPOINT ["tail","-f","/var/log/nginx/access.log"],那么启动的
时候镜像就执行了这个里面的内容,如果你像上面带参数的话就相当于在这个执行的内容后面再加入参数。
案例:
如果我们的dockerfile中有a中的这句话然后我们启动我们的docker:
#docker run -itd --name test image(镜像名) /bin/bash -c
此时就相当于我们启动docker的时候执行了:
docker run -itd --name test image(镜像名) tail -f /var/log/nginx/access.log /bin/bash -c
这个命令明显就不对,会发生报错
总结:
二者只能写一条,如果写了多条,那么只有最后一条生效。容器启动时才运行,运行时机相同。
ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖
CMD与ENTRYPOINT两个同时存在哪个生效?
如果在Dockerfile中同时写了ENTRYPOINT和CMD,并且CMD指令不是一个完整的可执行命令,
那么CMD指定的内容将会作为ENTRYPOINT的参数。
FROM ubuntu
ENTRYPOINT ["rm", "docker2"]
CMD ["-rf"]
真正的命令:rm docker2 -rf
如果在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD是一个完整的指令,那么它们两个会
互相覆盖,谁在最后谁生效
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ls -al
执行ls -al,top -b不会执行
dockerfile优化
编译一个简单的nginx成功以后发现好几百M。
1、RUN 命令要尽量写在一条里,多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会
建立一层,多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,
还容易出错。RUN书写时的换行符是\
2、每次进行依赖安装后,记得yum clean all【centos】
# yum clean all 清除缓存
3、选择比较小的基础镜像。Alpine Linux
Alpine linux系统:
1、小巧:和busybox一样小巧,最小的Docker镜像只有5MB;
2、简单:软件的搜索、安装、删除、升级都非常方便。
3、适合容器使用:由于小巧、功能完备,非常适合作为容器的基础镜像。
编写带有中文环境的centos7系统镜像
现在从公共仓库下载下来的ceonos7镜像默认是没有中文字符的,有时候由于业务时需要支持中文的。所以我们需要先构建一个带有中文的centos7镜像,在将该镜像作为基础镜像去使用。
下载阿里yum原到存有Dockerfile的centos目录
[root@docker-server centos]# curl -o ./CentOS-Base.repo https://mirrors.aliyun/repo/Centos-7.repo
编写带有中文包的基础镜像
[root@docker-server centos]# vim Dockerfile
FROM daocloud.io/library/centos:7
# 基于官方centos7精简版基础镜像,添加中文支持
# 替换yum源
#COPY CentOS-Base.repo /etc/yum.repos.d/
# 更新软件
RUN yum -y upgrade
# 安装中文包
RUN yum install -y kde-l10n-Chinese
# 重新安装glibc-common
RUN yum -y reinstall glibc-common
# 编译生成语言库
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
# 设置语言默认值为中文,时区改为东八区
RUN echo 'LANG="zh_CN.UTF-8"' > /etc/locale.conf
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ENV LANG zh_CN.UTF-8
ENV LC_ALL zh_CN.UTF-8
[root@docker-server ~]# yum clean all
[root@docker-server ~]# docker build -t 192.168.157.129/jdsc/centos:v1.1 .
[root@docker-server ~]# docker push 192.168.157.129/jdsc/centos:v1.1
# 推送到harbor仓库
dockerfile编写jspgou商城
1.先将jdk和tomcat还有代码包上传到服务器中的/root目录下
[root@iZ8vb3lp570ckxi53yb66gZ ~]# yum install -y unzip
[root@iZ8vb3lp570ckxi53yb66gZ ~]# unzip jspgouV6.1-ROOT.zip --解压代码包
2.下载mariadb的镜像
[root@iZ8vb3lp570ckxi53yb66gZ ~]# docker pull daocloud.io/library/mariadb:5.5
[root@iZ8vb3lp570ckxi53yb66gZ ~]# docker run -itd --name mysql --net host -e MYSQL_ROOT_PASSWORD=123456 992bce5ed
[root@iZ8vb3lp570ckxi53yb66gZ ~]# mysql -uroot -p'123456' -P3306 -h127.0.0.1
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 10
Server version: 10.5.9-MariaDB-1:10.5.9+maria~focal mariadb binary distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> create database jspgou default charset=utf8; #创建数据库
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> \q
Bye
导入sql文件
[root@iZ8vb3lp570ckxi53yb66gZ ~]# mysql -uroot -p'123456' -P3306 -h127.0.0.1 -D jspgou < DB/jspgou.sql
编写带有中文包的基础镜像
[root@iZ8vb3lp570ckxi53yb66gZ ~]# cat Dockerfile
FROM daocloud.io/library/centos:7
# 基于官方centos7精简版基础镜像,添加中文支持
# 替换yum源
#COPY CentOS-Base.repo /etc/yum.repos.d/
# 更新软件
RUN yum -y upgrade
# 安装中文包
RUN yum install -y kde-l10n-Chinese
# 重新安装glibc-common
RUN yum -y reinstall glibc-common
# 编译生成语言库
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
# 设置语言默认值为中文,时区改为东八区
RUN echo 'LANG="zh_CN.UTF-8"' > /etc/locale.conf
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ENV LANG zh_CN.UTF-8
ENV LC_ALL zh_CN.UTF-8
[root@iZ8vb3lp570ckxi53yb66gZ ~]# docker build -t my/c7:1.1 .
开始制作dockerfile
[root@iZ8vb3lp570ckxi53yb66gZ ~]# cd /opt/
[root@iZ8vb3lp570ckxi53yb66gZ opt]# mkdir jspgou
[root@iZ8vb3lp570ckxi53yb66gZ opt]# cd jspgou/
[root@iZ8vb3lp570ckxi53yb66gZ jspgou]# cp /root/jdk-8u191-linux-x64.tar.gz /root/apache-tomcat-9.0.68.tar.gz .
[root@iZ8vb3lp570ckxi53yb66gZ jspgou]# cp -r /root/ROOT/ .
[root@iZ8vb3lp570ckxi53yb66gZ jspgou]# ls
apache-tomcat-9.0.68.tar.gz jdk-8u191-linux-x64.tar.gz ROOT
修改代码连接数据库密码
[root@iZ8vb3lp570ckxi53yb66gZ jspgou]# vim ROOT/WEB-INF/config/jdbc.properties
在数据库密码哪里写上密码:123456
[root@iZ8vb3lp570ckxi53yb66gZ jspgou]# tar czvf ROOT.tar.gz ROOT/
编写jspgou的dockerfile
[root@iZ8vb3lp570ckxi53yb66gZ jspgou]# cat Dockerfile #编写dockerfile
# This my first Dockerfile
# Version 1.0
FROM my/c7:1.1
ENV JAVA_HOME /usr/local/jdk1.8.0_191
ENV TOMCAT_HOME /usr/local/apache-tomcat-9.0.68
ENV PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
ENV CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
ADD apache-tomcat-9.0.68.tar.gz /usr/local/
ADD jdk-8u191-linux-x64.tar.gz /usr/local/
RUN rm -rf /usr/local/apache-tomcat-9.0.68/webapps/*
ADD ROOT.tar.gz /usr/local/apache-tomcat-9.0.68/webapps/
RUN rm -rf apache-tomcat-9.0.68.tar.gz jdk-8u191-linux-x64.tar.gz
EXPOSE 8080
ENTRYPOINT ["/usr/local/apache-tomcat-9.0.68/bin/catalina.sh","run"]
[root@iZ8vb3lp570ckxi53yb66gZ jspgou]# docker build -t test/jspgou:1.1 .
[root@iZ8vb3lp570ckxi53yb66gZ jspgou]# docker images | grep test
test/jspgou 1.1 e3f75cc04ad9 2 minutes ago 845MB
运行镜像
[root@iZ8vb3lp570ckxi53yb66gZ jspgou]# docker run -itd --name tomcat --net host 611d11a
端口转发
使用端口转发解决容器端口访问问题
-p
-p:创建应用容器的时候,一般会做端口映射,这样是为了让外部能够访问这些容器里的应用。
可以用多个-p指定多个端口映射关系。
mysql应用端口转发:
查看本地地址:
[root@yixuan ~]# ip a
...
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:9c:bf:66 brd ff:ff:ff:ff:ff:ff
inet 192.168.246.141/24 brd 192.168.246.255 scope global dynamic ens33
valid_lft 5217593sec preferred_lft 5217593sec
inet6 fe80::a541:d470:4d9a:bc29/64 scope link
valid_lft forever preferred_lft forever
运行容器:使用-p作端口转发,把本地3307转发到容器的3306,其他参数需要查看发布容器的页面提示
[root@yj ~]# docker pull daocloud.io/library/mysql:5.7
[root@yj ~]# docker run -itd --name mysql1 -p 3307:3306 -e MYSQL_ROOT_PASSWORD=Qf@123! daocloud.io/library/mysql:5.7
a4327dbddf665b4302c549320bff869b8a027c2e1eead363d84ce5d06acf2698
-e MYSQL_ROOT_PASSWORD= 设置root密码。
-e MYSQL_DATABASE= 设置要创建的库
通过本地IP:192.168.246.141的3307端口访问容器mysql1内的数据库,出现如下提示恭喜你
1.安装一个mysql客户端
[root@yj ~]# yum install -y mysql
2.登录
[root@yj ~]# mysql -uroot -p'Qf@123!' -h 192.168.246.141 -P3307
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.26 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]>
-P(大P)
当使用-P标记时,Docker 会随机映射一个 32768~49900 的端口到内部容器开放
的网络端口,无需手动指定端口。
[root@yj ~]# docker pull daocloud.io/library/redis
[root@yj ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
daocloud.io/library/redis latest 598a6f110d01 2months ago 118MB
[root@yj ~]# docker run --name myredis -P -d daocloud.io/library/redis
ca06a026d84a0605d9a9ce6975389a79f4ab9a9a043a03f088cd909c1fe52e29
[root@yj ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ca06a026d84a daocloud.io/library/redis "docker-entrypoint.s…" 22 seconds ago Up 21 seconds 0.0.0.0:32768->6379/tcp myredis
从上面的结果中可以看出,本地主机的32768端口被映射到了redis容器的6379端口上,也就是说访问本机的32768端口即可访问容器内redis端口。
在别的机器上通过上面映射的端口32768连接这个容器的redis
[root@docker-server2 ~]# yum install -y redis
[root@docker-server2 ~]# redis-cli -h 192.168.246.141 -p 32768
192.168.246.141:32768> ping
PONG
192.168.246.141:32768>
容器卷
把本地宿主机上面的某一个目录挂载到容器里面的目录去。这两个目录都不用提前存在,会自动创建 本质上是一个目录挂载,将容器内的目录挂载到虚拟机上
新卷只能在容器创建过程当中挂载
[root@yj ~]# docker run -it --name testnginx -v /test:/test2 daocloud.io/library/nginx /bin/bash
root@86320e734cd1:/# ls
root@86320e734cd1:/# ctrl+p+q #退出
测试:
[root@yj ~]# cd /test/
[root@yj test]# ls
[root@yj test]# touch a.txt
[root@yj test]# cd
[root@yj ~]# docker exec -it testnginx /bin/bash
root@86320e734cd1:/# cd test2/
root@86320e734cd1:/test2# ls
a.txt
共享文件:
[root@yj ~]# mkdir /dir
[root@yj ~]# vim /dir/a.txt
123
[root@yj ~]# docker run -it --name testnginx2 -v /dir/a.txt:/dir1/a.txt daocloud.io/library/nginx /bin/bash
root@f899be627552:/# cat dir1/a.txt
123
root@f899be627552:/#
共享其他容器的卷(与其他容器用同一个卷)
[root@yixuan ~]# docker run -it --name testnginx1 --volumes-from testnginx daocloud.io/library/nginx /bin/bash
root@50e6f726335c:/# ls
bin dev home lib64 mnt proc run srv test2 usr
boot etc lib media opt root sbin sys tmp var
root@50e6f726335c:/# cd test2/
root@50e6f726335c:/test2# ls
a.txt
实际应用中可以利用多个-v选项把宿主机上的多个目录同时共享给新建容器:
比如:
# docker run -it -v /abc:/abc -v /def:/def 1ae9
#当前目录$PWD
# docker run -it --name testnginx4 -v $PWD:/test3 -v /abc:/abc daocloud.io/library/nginx /bin/bash
docker数据存储位置
查看存储路径
[root@yixuan ~]# docker info | grep Root
Docker Root Dir: /var/lib/docker
修改默认存储位置:
在dockerd的启动命令后面追加--data-root参数指定新的位置
[root@yixuan ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --data-root=/data
[root@yixuan ~]# systemctl daemon-reload
[root@yixuan ~]# systemctl restart docker
查看是否生效:
[root@yixuan ~]# docker info | grep Root
Docker Root Dir: /data
Docker --link实现容器互联
1.1、容器间通过IP进行网络访问
1.2、容器间通过容器名或容器id进行网络访问
容器互联
--link可以通过容器名互相通信,容器间共享环境变量。
--link主要用来解决两个容器通过ip地址连接时容器ip地址会变的问题.
语法:
--link 源容器名:连接别名 #连接别名可以和容器名一致,也可以不指定
先创建mysql容器
[root@docker-server ~]# docker run -dti --name db-server --restart=always -e MYSQL_ROOT_PASSWORD=QianFeng@123! -e MYSQL_DATABASE=blog mysql:5.7
在创建wordpress容器
[root@docker-server ~]# docker run -dti --name blog --restart=always -v /web:/var/www/html -p 80:80 --link db-server:mysql wordpress
--link db:mysql:将容器与另一个名为db-server的容器连接起来,并设置别名为 mysql,以便在后续操作中引用该容器。
[root@docker-server ~]# cat /etc/hosts #可以看到做了host解析
1.3、容器互联:创建自定义网络的方式
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
# --driver bridge:指定网络的驱动程序为bridge。创建一个基于桥接的网络,允许容器通过Docker主机进行通信。
# --subnet 192.168.0.0/16:设置网络的子网为 192.168.0.0/16。
# --gateway 192.168.0.1:指定网络网关 192.168.0.1。
docker网络
容器网络分类
注:面试用,用了编排之后就没有用了
查看当前网络:
[root@yj ~]# docker network list
NETWORK ID NAME DRIVER SCOPE
9b902ee3eafb bridge bridge local
140a9ff4bb94 host host local
d1210426b3b0 none null local
docker安装后,默认会创建三种网络类型,bridge、host和none
1、bridge:桥接网络
默认情况下启动、创建容器都是用该模式,所以每次docker容器重启时会按照顺序获取对应ip地址。
2、none:无指定网络
启动容器时,可以通过--network=none,docker容器不会分配局域网ip
3、host:主机网络
docker容器和主机共用一个ip地址。
使用host网络创建容器:
[root@yj ~]# docker run -it --name testnginx2 --net host 98ebf73ab
[root@yj ~]# netstat -lntp | grep 80
tcp6 0 0 :::80 :::* LISTEN 3237/docker-proxy
浏览器访问宿主ip地址
4、固定ip
创建固定Ip的容器
4.1、创建自定义网络类型,并且指定网段
[root@yj ~]# docker network create --subnet=192.168.0.0/24 staticnet
4efd309244c6ad70eda2d047a818a3aec5b162f5ca29fb6024c09a5efbf15854
通过docker network ls可以查看到网络类型中多了一个staticnet:
[root@yj ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
9b902ee3eafb bridge bridge local
140a9ff4bb94 host host local
d1210426b3b0 none null local
4efd309244c6 staticnet bridge local
4.2、使用新的网络类型创建并启动容器
[root@yj ~]# docker run -itd --name userserver --net staticnet --ip 192.168.0.2 daocloud.io/library/centos:7
通过docker inspect可以查看容器ip为192.168.0.2:
[root@yj ~]# docker inspect userserver | grep -i ipaddress
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "192.168.0.2",
关闭容器并重启,发现容器ip并未发生改变
docker资源限制
为什么做资源限制?
在使用 docker 运行容器时默认情况下在宿主机上面运行的容器是没有做资源使用上限的,一台主机上可能会运行几百个容器,这些容器虽然互相隔离,但是底层却使用着相同的 CPU、内存、磁盘和网络资源。那么容器使用的上限就是宿主机剩余的资源,比如你宿主机还有10G的剩余内存,它也能给你用完,你有百分之百的cpu使用率也能给你占用到百分之百。如果不对容器使用的资源进行限制,那么容器之间会互相影响,小的来说会导致容器资源使用不公平;大的来说,可能会导致主机和集群资源耗尽,服务完全不可用。
CPU 和内存的资源限制已经是比较成熟和易用,能够满足大部分用户的需求。磁盘限制也是不错的,虽然现在无法动态地限制容量,但是限制磁盘读写速度也能应对很多场景。
至于网络,docker 现在并没有给出网络限制的方案,也不会在可见的未来做这件事情,因为目前网络是通过插件来实现的,和容器本身的功能相对独立,不是很容易实现,扩展性也很差。
资源限制可以让我们为容器(应用)设置合理的 CPU、内存资源,方便管理。
docker里面的资源给谁做什么样的限制?给容器做限制。
系统压力测试工具stress
stress是一个linux下的压力测试工具,专门为那些想要测试自己的系统,完全高负荷和监督这些设备运行的用户。
cpu资源限制
限制CPU Share
什么是cpu share:容器使用cpu的比例
什么是 CPU Shares?
在Docker中,--cpu-shares
参数用于控制容器之间的相对CPU资源分配。它并不表示容器可以使用的绝对CPU时间或百分比,而是一个相对权重值。默认情况下,每个容器的 --cpu-shares
值为 1024,但这只是一个参考值,可以设置为任何正整数。
CPU Shares 的工作原理
当主机上有多个容器同时运行时,Docker会根据每个容器的 --cpu-shares
值来决定它们各自能够获得多少CPU时间。具体来说,每个容器所获得的CPU时间将是其 --cpu-shares
值在所有容器总和中的比例。
示例说明
假设主机上有两个容器 A 和 B:
- 如果 A 和 B 的
--cpu-shares
都设置为 1024,则它们各自将获得 50% 的 CPU 时间(假定没有其他进程影响)。 - 如果 A 的
--cpu-shares
设置为 1024,而 B 的设置为 512,则 A 将获得大约 66% 的 CPU 时间,而 B 将获得大约 33% 的 CPU 时间(1024 / (1024 + 512) ≈ 66%, 512 / (1024 + 512) ≈ 33%)。 - 如果只有一个容器在运行,并且该容器的
--cpu-shares
设置为 512,则该容器理论上可以获得 100% 的 CPU 时间,因为此时没有其他容器竞争CPU资源。
CPU Shares 的灵活性
-c 或 --cpu-shares
的值并不局限于 1024,可以设置任何正整数。无论设置的具体数值是多少,Docker都会根据比例来分配CPU时间。
优点
- 公平性:确保所有容器能够相对公平地分享可用的CPU资源。
- 灵活性:可以根据需要调整各个容器的优先级,从而更好地管理资源。
缺点
- 非确定性:无法精确控制每个容器可以使用的CPU时间量,只能做到相对的权重分配。
- 受系统负载影响:实际CPU使用还可能受主机负载和其他进程的影响。
实验
机器是 4 核 CPU,因此运行一个stress容器,使用 stress 启动 4 个进程来产生计算压力:(无CPU限制)
[root@yj ~]# docker pull progrium/stress #下载测试工具,就是为了测试 [root@yj ~]# yum install -y htop [root@yj ~]# docker run --rm -it progrium/stress --cpu 4 stress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd stress: dbug: [1] using backoff sleep of 12000us stress: dbug: [1] --> hogcpu worker 4 [6] forked stress: dbug: [1] using backoff sleep of 9000us stress: dbug: [1] --> hogcpu worker 3 [7] forked stress: dbug: [1] using backoff sleep of 6000us stress: dbug: [1] --> hogcpu worker 2 [8] forked stress: dbug: [1] using backoff sleep of 3000us stress: dbug: [1] --> hogcpu worker 1 [9] forked
在另外一个 terminal 使用 htop 查看资源的使用情况:
上图中看到,CPU 四个核资源都达到了 100%。
为了比较,另外启动一个 share 为 512 的容器:
1.先将没有做限制的命令运行起来 [root@yj ~]# docker run --rm -it progrium/stress --cpu 4 2.在开启一个终端,运行做了CPU限制的命令 [root@yj ~]# docker run --rm -it -c 512 progrium/stress --cpu 4 stress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd stress: dbug: [1] using backoff sleep of 12000us stress: dbug: [1] --> hogcpu worker 4 [6] forked stress: dbug: [1] using backoff sleep of 9000us stress: dbug: [1] --> hogcpu worker 3 [7] forked stress: dbug: [1] using backoff sleep of 6000us stress: dbug: [1] --> hogcpu worker 2 [8] forked stress: dbug: [1] using backoff sleep of 3000us stress: dbug: [1] --> hogcpu worker 1 [9] forked 3.在开启一个终端执行htop命令 [root@yj ~]# htop
因为默认情况下,容器的 CPU share 为 1024,所以这两个容器的 CPU 使用率应该大致为 2:1,下面是启动第二个容器之后的监控截图:
两个容器分别启动了四个 stress 进程,第一个容器 stress 进程 CPU 使用率都在 60% 左右,第二个容器 stress 进程 CPU 使用率在 30% 左右,比例关系大致为 2:1,符合之前的预期。
限制CPU 核数
限制容器能使用的 CPU 核数
从 1.13 版本之后,docker 提供了 --cpus 参数可以限定容器能使用的 CPU 核数。这个功能可以让我们更精确地设置容器 CPU 使用量,是一种更容易理解也因此更常用的手段. --cpus 后面跟着一个浮点数,代表容器最多使用的核数,可以精确到小数点二位,也就是说容器最小可以使用 0.01 核 CPU。
在容器里启动三个 stress 来跑 CPU 压力,如果不加限制,这个容器会导致 CPU 的使用率为 300% 左右(也就是说会占用三个核的计算能力)。
限制容器只能使用 1.5 核数 CPU:
# docker run --rm -it --cpus 1.5 progrium/stress --cpu 3
stress: info: [1] dispatching hogs: 3 cpu, 0 io, 0 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 9000us
stress: dbug: [1] --> hogcpu worker 3 [6] forked
stress: dbug: [1] using backoff sleep of 6000us
stress: dbug: [1] --> hogcpu worker 2 [7] forked
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogcpu worker 1 [8] forked
可以看到,每个 stress 进程 CPU 使用率大约在 50%,总共的使用率为 150%,符合 1.5 核的设置。
如果设置的 --cpus 值大于主机的 CPU 核数,docker 会直接报错:
# docker run --rm -it --cpus 8 progrium/stress --cpu 3 #启用三个进程做测试
docker: Error response from daemon: Range of CPUs is from 0.01 to 4.00, as there are only 4 CPUs available.
See 'docker run --help'.
如果多个容器都设置了 --cpus ,并且它们之和超过主机的 CPU 核数,并不会导致容器失败或者退出,这些容器之间会竞争使用 CPU,具体分配的 CPU 数量取决于主机运行情况和容器的 CPU share 值。也就是说 --cpus 只能保证在 CPU 资源充足的情况下容器最多能使用的 CPU 数,docker 并不能保证在任何情况下容器都能使用这么多的 CPU(因为这根本是不可能的)。
CPU 绑定
限制容器运行在某个 CPU 核上
注:一般并不推荐在生产中这样使用
案例:
假如主机上有 4 个核,可以通过 --cpuset 参数让容器只运行在前两个核上:
docker run --rm -it --cpuset-cpus=0,1 progrium/stress --cpu 2
cpu编号从0开始,cpu0,cpu1,cpu2......(top命令可以查看cpu核)
(二次开发的htop查看端核从cpu1开始)
top或htop命令监控可以看到只有前面两个核 CPU 达到了 100% 使用率。
mem资源限制
docker 默认没有对容器内存进行限制,容器可以使用主机提供的所有内存。
不限制内存带来的问题
如果某个容器运行了恶意的内存消耗软件,或者代码有内存泄露,很可能会导致主机内存耗尽,因此导致服务不可用。可以为每个容器设置内存使用的上限,一旦超过这个上限,容器会被杀死,而不是耗尽主机的内存。
限制内存带来的问题
限制内存上限虽然能保护主机,但是也可能会伤害到容器里的服务。如果为服务设置的内存上限太小,会导致服务还在正常工作的时候就被 OOM 杀死;如果设置的过大,会因为调度器算法浪费内存。
合理做法
1. 为应用做内存压力测试,理解正常业务需求下使用的内存情况,然后才能进入生产环境使用 2. 一定要限制容器的内存使用上限,尽量保证主机的资源充足,一旦通过监控发现资源不足,就进行扩容或者对容器进行迁移 3. 尽量不要使用 swap,swap 的使用会导致内存计算复杂。
docker 限制容器内存使用量:
-m --memory:容器能使用的最大内存大小,最小值为 4m
如果限制容器的内存使用为 64M,在申请 64M 资源的情况下,容器运行正常(如果主机上内存非常紧张,并不一定能保证这一点):
docker run --rm -it -m 64m progrium/stress --vm 1 --vm-bytes 64M --vm-hang 0
容器可以正常运行。
参数解释:
-m 64m:限制你这个容器只能使用64M
--vm:生成几个占用内存的进程
--vm-bytes 64M:容器里面进程使用的内存。
hang:就是卡在这里。
而如果申请 150M 内存,会发现容器里的进程被 kill 掉了(worker 6 got signal 9,signal 9 就是 kill 信号)
docker run --rm -it -m 64m progrium/stress --vm 1 --vm-bytes 150M --vm-hang 0
磁盘I/O资源限制
对于磁盘来说,考量的参数是容量和读写速度,因此对容器的磁盘限制也应该从这两个维度出发。目前 docker 支持对磁盘的读写速度进行限制,但是并没有方法能限制容器能使用的磁盘容量(一旦磁盘 mount 到容器里,容器就能够使用磁盘的所有容量)。
第一种是:磁盘的读写速率的限制。第二种是:磁盘的读写频率的限制
读写速率就是一秒钟可以读多少数据写多少数据,读写频率就是:多少秒读写一次。
版权声明:本文标题:docker容器 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1729507580a1203723.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论