【05】循序渐进学 docker:系统资源和网络
写在前面的话
在上一篇学习 Dockerfile 的时候其实还有几个相当重要得关键中没有谈到,但没关系,在后面的内容会单独提出来一个一个的学习。这里就先谈谈关于资源的控制个容器的网络~
资源限制
其实对于容器的资源使用,无外乎在意 3 个方面,内存,CPU,IO,但 IO 很多时候是没法避免的,所以更多的还是通过内存和 CPU来进行资源限制。
【1】限制内存:
docker run --memory=200M centos
--memory:配置 200M,但这并不意味容器最大内存是 200M,在没额外对 Swap 进行限制时,Swap 和内存对等,所以是 400M。
--memory-swap:限制 Swap。
【2】CPU 限制:
docker run --cpu-shares=10 centos
限制 CPU,并不是限制使用几核,而是权重占比。
假如一个容器 10,一个 20,另外一个 10,那 CPU 占用实际是 25%,50% 和 25%。
关于资源限制的其他参数可以通过 --help 看到,这里也就谈谈使用较多的,其他都相对于比较冷门,需要的时候再去查。
Network namespace
在学习容器网络之前,可以先学习一下 Linux 网络名称空间,有助于更好的理解容器网络~
【1】先建立两个 network namespace,并启动内部的网卡:
# 查看本机的 network namespace ip netns list # 添加两个 network namespace ip netns add ns-1 ip netns add ns-2 # 查看 network namespace 的网卡信息 ip netns exec ns-1 ip a ip netns exec ns-2 ip a # 启动 lo 网卡 ip netns exec ns-1 ip link set dev lo up ip netns exec ns-2 ip link set dev lo up # 再度查看网卡信息 ip netns exec ns-1 ip a ip netns exec ns-2 ip a
结果如图:
此时,lo 网卡启动状态显示 UNKNOWN 状态,情景就好像一根网线只插了一头。
【2】新建两个网卡,并将它们各自分到 network namespace:
# 新建两个网卡 ip link add veth-1 type veth peer name veth-2 # 查看网卡连接信息 ip link # 将网卡分别分配到不同的 network namespace ip link set veth-1 netns ns-1 ip link set veth-2 netns ns-2 # 再度查看网卡信息 ip link # 查看 network namespace 中的网卡信息 ip netns exec ns-1 ip link ip netns exec ns-2 ip link
结果如图:
在网卡刚创建时,属于本机。但当将网卡分配到别的命名空间后,本机就不存在了。而是存在于各自的命名空间。
这就好比新加了一条网线,本来两头都是插在本机的,但现在将它拔了出来,一头插在了 ns-1 的网络命名空间上,另一头插在了 ns-2 上面。
【3】将两个网卡都启动起来并配置上 IP,测试连通信:
# 给 network namespace 中的网卡配置 IP 地址 ip netns exec ns-1 ip addr add 192.168.1.1/24 dev veth-1 ip netns exec ns-2 ip addr add 192.168.1.2/24 dev veth-2 # 启动 network namespace 中的网卡 ip netns exec ns-1 ip link set dev veth-1 up ip netns exec ns-2 ip link set dev veth-2 up # 查看配置后的网卡信息 ip netns exec ns-1 ip a ip netns exec ns-2 ip a # 测试连通信性 ip netns exec ns-1 ping 192.168.1.2
结果如图:
可以看到两个命名空间已经可以独立的通信了,但本机其实和这个两个网卡是不通的。
这样就产生了一个存在本机,但是又独立于本机,能够互相通信的网络,最终达到的效果类似下图:
以上的内容完全是作为帮助理解,只需要知道有这么一回事就行。
带着这个基础,再来看容器网络。
容器网络
先看容器到底是怎么通信的:
和前面的图很像。但相比于那个图,本机多了一个 docker0 网卡,简单的可以把这个 docker0 假设成一个交换机,一根网线接到互联网,然后我们的电脑都可以用网线连接上去,不仅内网互通,还能上网。
这样的技术放在容器的实现里面就是通过本机的防火墙的 NAT 转发实现。
docker 自带了 3 种网络:
docker network ls
结果如图:
在三种网络中,默认是 bridge(桥接),其他两种用的相对较少。
host:容器和本机一起共享端口,共享一个 IP。
none:“孤儿网络”,建立一个容器,完完全全独立。
当然,除了这 3 种网络,还可以自己建立一个其他名称的网络,但是在接触 overlay 网络之前,你的网络的 DRIVER 终究逃不脱这 3 种。
比如新建一个网络:
docker network create -d bridge my-network
结果如图:
通过 --network 参数将新建立的容器指定使用这个网络~
docker run --name b3 --network my-network -it -d busybox /bin/sh -c "while true; do sleep 300; done"
后面执行个死循环的目的是为了容器不自动退出。
docker container inspect b3
查看容器的详细信息,里面的 Networks 项变成了 my-network,默认网段也变了。
再新建一个容器,让它属于默认的网络:
docker run --name b4 -it -d busybox /bin/sh -c "while true; do sleep 300; done"
此时,用新的网络来测试和默认的网络的连通性:
结果:无法通信。
查看某个网络的接入情况需要借助 brctl 了,默认不存在,需要自己安装:
yum install bridge-utils -y
查看:
brctl show
结果如下:
有两个桥接网络,每个都连接了一个网卡,docker0 我们知道,但是 br-xxx 是啥?
其实,br-xxx 就是手动创建的 my-network,xxx 部分就是 network 的 ID,可以查看:
docker network ls
查看本机目前的网络情况:
结合上面的图,30 和 32 网卡其实是连接到 docker0 和 br-xxx 的。
这时候的 docker0 和 br-xxx 就相当于两个网络接口,30 和 32 网卡就像两条网线,一头已经插在了这两个接口上。那另外一头,自然就插在了容器里面,这样就实现了容器与当前主机的通信了。
再配合防火墙转发规则,那么就实现了容器的上网。
查看指定网络到底有哪些容器连接到上面:
docker network inspect my-network
结果如图:
但现在有一个需求来了:
有一个机器,需要以容器的形式运行一个 MySQL 数据库,有一个同样以容器运行的程序需连接到这个数据库,但是由于容器被分配到的 IP 地址是自动分配的,下一次重新构建可能就变了,那怎么保证下次不需要修改配置依然能够连接到数据库呢?
--link:将一个容器连接到另外一个容器。
先一次性删除掉之前的建立的所有容器,在不停止容器的前提下依然删除容器:-f 参数,强制执行:
docker container rm -f $(docker ps -qa)
【1】新建两个容器,都隶属相同的默认网络:
docker run --name b1 -it -d busybox /bin/sh -c "while true; do sleep 300; done" docker run --name b2 -it -d busybox /bin/sh -c "while true; do sleep 300; done"
【2】通过容器名称测试容器连通性:
docker exec -it b1 ping b2
结果如图:
结果:通过容器名称是无法通信。
【3】新建一个容器,连接到 b1:
docker run --name b3 --link b1 -it -d busybox /bin/sh -c "while true; do sleep 300; done"
再度测试和 b1 与 b2 的连通性:
docker exec -it b3 ping b1 docker exec -it b3 ping b2
结果如图:
结果:b3 在使用 --link 连接到 b1 后可以通过容器名称直接进行通信,但反过来不行。
【4】再度建立一个容器,link 到 b1:
docker run --name b4 --link b1 -it -d busybox /bin/sh -c "while true; do sleep 300; done"
测试 b4 和 b1,b3 的连通性:
docker exec -it b4 ping b1 docker exec -it b4 ping b3
结果如图:
结果:单独 link 的容器正向可以通信,反过来不行。
由此,可以暂时得出这样一个结论:
在默认的 bridge 网络中,可以使用 --link 参数实现容器通过容器名称访问容器,但是这个参数的作用是单向的。
上面的方法实现了简单的需求,但是每次都需要指定,岂不麻烦?再次删除掉所有容器,用自己创建网络测试:
【1】创建两个容器,让它们属于我们自己建立的网络:
docker container rm -f $(docker ps -qa) docker run --name b1 --network my-network -it -d busybox /bin/sh -c "while true; do sleep 300; done" docker run --name b2 --network my-network -it -d busybox /bin/sh -c "while true; do sleep 300; done"
测试网络的连通性:
docker exec -it b1 ping b2 docker exec -it b2 ping b1
结果如图:
结果:自动实现互相通过容器名称通信。
是不是真香?再新建一个容器试试?
docker run --name b3 --network my-network -it -d busybox /bin/sh -c "while true; do sleep 300; done"
测试连通性:
docker exec -it b3 ping b1 docker exec -it b3 ping b2
结果如图:
完全没问题,由此可以得出另外一条结论:
在自建的网络中容器,默认会自动互相 link,由此能够实现直接通过容器名称进行互相通信。
这就很好解决了上面 IP 会变但不想修改配置照样连上数据库,直接使用容器名称代替 IP 就行。
结论:在容器中,需要摒弃之前在虚拟机应用时代关于 IP 的重视程度,在容器应用中,IP 几乎可以不需要理会。
端口映射
之前 Flask 的例子已经发现了,当容器中启动某个端口的服务,宿主机以外的其他用户是不能访问的。
那么如何才能访问呢?这就得依靠端口映射,将 docker 容器的端口转换成宿主机的某个端口。
其实就是 2 个参数,-p 和 -P:
-p:将宿主机的某个端口映射到容器中的某个端口。
-P:将容器中的所有端口映射成宿主机 32768 之上的随机端口。
对之前的 Flask 项目做改进:app.py 如下
from flask import Flask from redis import Redis import os import socket app = Flask(__name__) redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379) @app.route('/') def hello(): redis.incr('hits') return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (redis.get('hits'),socket.gethostname()) if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True)
项目是这样的,用户在每请求一次,redis 给这个值增加 1,进而实现页面显示的数字加 1 的效果:
mkdir flask-redis cd flask-redis/ vim app.py
添加 Dockerfile:
FROM python:2.7 LABEL maintainer="Dylan <1214966109@qq.com>" COPY app.py /app/ RUN pip install flask && pip install redis WORKDIR /app/ EXPOSE 5000 CMD ["python", "app.py"]
构建镜像:
docker build -t dylan/flask-demo:v1.0 .
再运行一个 redis 容器,和之前 MySQL 问题类似,这里也准备使用容器名称来连接,因为只连接了一个服务,直接使用 --link 就行~
【1】运行 redis 容器:
docker run -d --name redis redis
【2】运行刚刚的 flask-redis:
docker run -d --name flask-redis-demo --link redis -e REDIS_HOST=redis dylan/flask-demo:v1.0
-e:给容器设置一个环境变量,因为程序代码会从环境变量中获取 redis 的地址,如果没有,才默认使用 127.0.0.1。
这样写的达到了灵活配置的目的。
curl http://172.17.0.3:5000
在本机通过 curl 访问容器 IP 加端口就能够访问到内容了,如下图:
那为啥之前那个简单的 flask 项目在宿主机无法直接访问呢?原因很简单。
因为监听 IP 的原因,之前监听的是 127.0.0.1 只能本机访问,而这里监听的是 0.0.0.0 都允许~
【3】再运行一个随机映射的项目:
docker run -d --name flask-redis-demo1 -P --link redis -e REDIS_HOST=redis dylan/flask-demo:v1.0
通过查看本机的端口可知是 32769 端口,访问测试:
【4】再运行一个指定端口的:
docker run -d --name flask-redis-demo2 -p 8080:5000 --link redis -e REDIS_HOST=redis dylan/flask-demo:v1.0
将它映射到 8080,访问测试:
小结
对于资源管理和网络的知识暂时谈到这里,后面会谈到另外一种网络 DRIVER(overlay)网络~
【05】循序渐进学 docker:系统资源和网络的更多相关文章
- 【01】循序渐进学 docker:到底是啥
写在前面的话 首先说一下,我本身是做运维的,4 年工作,多家公司.所以可能接下来谈到的更多的是一些在工作过程中积累的个人看法.且有些并不具备普遍性,有不合适的地方,全当我在吹牛逼就行. 一开始我们得谈 ...
- 【09】循序渐进学 docker:docker swarm
写在前面的话 至此,docker 的基础知识已经了解的差不多了,接下来就来谈谈对于 docker 容器,我们如何来管理它. docker swarm 在学习 docker swarm 之前,得先知道容 ...
- 【08】循序渐进学 docker:docker compose
写在前面的话 在之前的操作中,即使是单个容器每次都需要敲很长的命令,当需要多个容器组合着用的时候更加麻烦,此时我们急需找到一种一次配置,随便运行的方法. 这就是这一节重点,单机容器编排工具:docke ...
- 【07】循序渐进学 docker:数据持久化
写在前面的话 学到这里相信有心的朋友都发现问题了,我们每次都会去删掉容器,在创建新的容器.那数据怎么办?岂不删库跑路了? 就算不是数据库,假设公司有日志保留的需求,那每一次发布岂不日志都被干掉了? D ...
- 【06】循序渐进学 docker:跨主机通信
写在前面的话 目前解决容器跨主机通信的方案有很多种,这里给出的只是其中的一种,而且还不是最好的方案,不过归根结底,大同小异.在学习 docker swarm 之前,大家可以先看看这种. 啥是 over ...
- 【循序渐进学Python】15.网络编程
Python 内置封装了很多常见的网络协议的库,因此Python成为了一个强大的网络编程工具,这里是对Python的网络方面编程的一个简单描述. 1. 常用的网络设计模块 在标准库中有很多网络设计相关 ...
- 【04】循序渐进学 docker:Dockerfile
写在前面的话 从前面我们简单的了解了镜像,也运行了容器,各种官方的镜像显然无法满足我们自己的需求,我们目的终究是运行自己的业务. 所以,本章节的 Dockerfile 就主要讲怎么在官方镜像的基础上制 ...
- 【03】循序渐进学 docker:基础命令
写在前面的话 之前谈了啥是 docker 和怎么安装 docker,这里就谈谈 docker 命令的使用,当然,这里的使用可能只是局限于 docker 的增删查改. 另外需要注意的是,为了图片的美观, ...
- 【02】循序渐进学 docker:如何安装
写在前面的话 我们接下来的操作都是 CentOS 7.5 以下完成的,为了避免你我结果不一致,建议你也采用 CentOS 7.5,原因如下: 1. 个人几年工作下来经历的公司,包括身边的运维朋友,90 ...
随机推荐
- Sqlserver ROW_NUMBER()
SELECT ROW_NUMBER() OVER (ORDER BY A.orderdate,A.orderid),* from Sales.Orders A
- 使用opencv-python画OpenCV LOGO
OpenCV2-Python 官方教程的练习 代码: #-*- coding:utf-8 -*- import numpy as np import cv2 img = np.zeros((512, ...
- Python解释器种类以及特点 (经典概括, 便于理解和记忆)
CPython c语言开发的 使用最广的解释器 IPython 基于cpython之上的一个交互式计时器 交互方式增强 功能和cpython一样 PyPy 目标是执行效率 采用JIT技术 对pytho ...
- 【LA11248 训练指南】网络扩容【最大流】
题意: 给定一个有向网络,每条边均有一个容量.问是否存在一个从点1到点N,流量为C的流.如果不存在,是否可以恰好修改一条弧的容量,使得存在这样的流? 分析: 先跑一遍最大流,如果最大流大于等于C,则输 ...
- 150. Evaluate Reverse Polish Notation (Stack)
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, ...
- IIS网站最大并发连接数
打开网站服务器IIS---[控制面板]-[管理工具]--[Internet信息服务IIS管理器] 打开应用程序池--找到网站对应使用的应用程序池--选择右侧[高级设置] 在[高级设置]窗口可看 ...
- vmware workstation环境下虚拟机固定ip的设置
一.准备 (1)vmware workstation (2)centOS 6.5 二.配置 采用nat模式对虚拟机进行固定ip配置,nat模式相当于在windows的操作系统下构建了一个独立的内部局域 ...
- 全新的css网站布局--Grid布局
Grid布局全新的css网站布局 CSS Grid 布局由两个核心组成部分是 wrapper(父元素)和 items(子元素). wrapper 是实际的 grid(网格),items 是 grid( ...
- [C++] Sign and magnitude,Ones' complement and Two's complement
Sign and magnitude,Ones' complement and Two's complement
- noi2729 Blah数集
Blah数集 大数学家高斯小时候偶然间发现一种有趣的自然数集合Blah,对于以a为基的集合Ba定义如下: (1) a是集合Ba的基,且a是Ba的第一个元素: (2)如果x在集合Ba中,则2x+1和3x ...