前言
- 原创学习笔记
- 第一次做markdown笔记,以后会努力做得更好的~
- 前半段用的是markdownpad+imgur,直到发现了VScode,才知道什么叫做神器...
- 1. 容器技术的发展史
- 2. docker的基本使用
- 3. docker 制作镜像
- 4. 容器的虚拟网络模型
- 5. docker存储卷
- 6. DockerFile的制作
- 7. 搭建私有registry
- 8. VMWARE_HARBOR
- 9. 资源限制
- 10. K8S
- 11. DevOps(持续集成和持续部署)
- 在宿主机上虚拟出多个内核,在内核上分别创建虚拟机;
- 直接在硬件资源上创建内核(跳过宿主机系统),在内核上创建虚拟机;
这样会造成严重的资源浪费,哪怕只想运行一个web服务,都要虚拟出一个主机
命名空间的分类如图:
因为用户命名空间在linux的支持版本较晚,也据定了centos6的内核版本不适合用docker,即使高版本内核可用也很不稳定;
因为虚拟机技术的资源浪费,由此诞生了第一种使用同一个内核,而不需要再分离出多个内核(节省资源)的容器技术Linux Container
LXC技术是利用自己创建的模板,对内核进行命名空间的划分,然后生成一个容器,在容器内运行多个进程,但这样有一个缺点是生成的容器内的数据很难迁移,模板生成也十分复杂;
所以就诞生了docker技术,docker技术的底层其实就是LXC,它其实是对LXC技术的封装;
命名空间是 Linux 内核一个强大的特性。每个容器都有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。
不同用户的进程就是通过 pid 命名空间隔离开的,且不同命名空间中可以有相同 pid。所有的 LXC 进程在 Docker 中的父进程为Docker进程,每个 LXC 进程具有不同的命名空间。同时由于允许嵌套,因此可以很方便的实现嵌套的 Docker 容器。
有了 pid 命名空间, 每个命名空间中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net 命名空间实现的, 每个 net 命名空间有独立的 网络设备, IP 地址, 路由表, /proc/net 目录。这样每个容器的网络就能隔离开来。Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一 个Docker 网桥 docker0 连接在一起。
容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication - IPC), 包括信号量、消息队列和共享内存等。然而同 VM 不同的是,容器的进程间交互实际上还是 host 上具有相同 pid 命名空间中的进程间交互,因此需要在 IPC 资源申请时加入命名空间信息,每个 IPC 资源有一个唯一的 32 位 id。
类似 chroot,将一个进程放到一个特定的目录执行。mnt 命名空间允许不同命名空间的进程看到的文件结构不同,这样每个命名空间 中的进程所看到的文件目录就被隔离开了。同 chroot 不同,每个命名空间中的容器在 /proc/mounts 的信息只包含所在命名空间的 mount point。
UTS("UNIX Time-sharing System") 命名空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 主机上的一个进程。
每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。
它相对于LXC的一大优点是可以很轻松的创建和自定义镜像,存储在云仓库中,在使用的时候拉取运行即可;
docker在一个容器中只运行一个进程,进程之间通过容器的方式进行通信,比如tomcat和Nginx;
docker可以将容器打包,它不再依赖内核的命名空间,而是拥有自己独立的命名空间,就使得自己的运行环境完全独立于平台,就实现了分发镜像的极大便利;
google早在十年前就秘密使用了docker技术和容器编排工具borg 后来docker公司为了盈利,发布了容器编排工具docker compose,docker machine,docker swarm(实现容器的资源管理),但此时google为了防止自己丧失容器编排技术的话语权,把内部成熟的borg用go语言重写了k8s,因为google丰富的容器使用经验,使得k8s碾压docker的容器编排工具
docker公司为了盈利,就把docker分为了社区版(更名moby)和企业版(docker) 为的往企业版docker引流,获取投资和利润;而相比之下,google成立CNCF委员会来脱离出google引导k8s的健康发展; 使得世界对k8s的支持呼声极高
docker在发展壮大起来后,开发了新的引擎libcontainer,抛弃了原来的LXC;又在社区版和企业版上吃相难看,其过河拆桥之行为与世界技术的发展背道而驰
容器技术的使用需要制定行业标准,CNCF完全有能力制定标准,而且为了保证不被docker一家公司控制,CNCF将docker排除在外,但是也给了docker一个改过自新的机会,让docker把自己开发的新引擎libcontainner更名为runC作为容器技术引擎的标准
- daemon:守护进程(后台进程) 用来拉取镜像和运行容器(容器是镜像的一个动态实例)
- docker client : docker的客户终端
- docker register: docker仓库 (用来存放镜像) + 用户认证功能
alpine:是轻量版,缺少测试工具,不建议使用
[root@sx ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
27c586590860 centos "/bin/bash" About a minute ago Up 59 seconds cent7
2685adbf571c redis "docker-entrypoint.s…" 5 hours ago Up 5 hours 0.0.0.0:6379->6379/tcp redis63
[root@sx ~]# docker commit cent7 sunxuxu/mycentos7:v1
sha256:fbf50e3ebc88857d42f3ee8a8c455f05e5e8526595d295f5c94f3f86d5f6add5
[root@sx ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sunxuxu/mycentos7 v1 fbf50e3ebc88 15 seconds ago 202MB
rabbitmq management 476495614692 11 days ago 194MB
redis alpine 72e76053ebb7 2 weeks ago 50.9MB
redis latest d3e3588af517 2 weeks ago 95MB
centos latest 9f38484d220f 2 months ago 202MB
registry latest f32a97de94e1 2 months ago 25.8MB
hello-world latest fce289e99eb9 5 months ago 1.84kB
[root@sx ~]# docker tag fbf50e3ebc88 sunxu/mycent:v2
[root@sx ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sunxuxu/mycentos7 v1 fbf50e3ebc88 54 seconds ago 202MB
sunxu/mycent v2 fbf50e3ebc88 54 seconds ago 202MB
rabbitmq management 476495614692 11 days ago 194MB
redis alpine 72e76053ebb7 2 weeks ago 50.9MB
redis latest d3e3588af517 2 weeks ago 95MB
centos latest 9f38484d220f 2 months ago 202MB
registry latest f32a97de94e1 2 months ago 25.8MB
hello-world latest fce289e99eb9 5 months ago 1.84kB
docker run -it --name containername --network bridge -h sunxu.com --dns 8.8.8.8 --rm image:tag
#network 指定网络模式 还有none host
#-h 指定docker容器的主机名
#dns 指定docker容器的dns服务器
#上面的参数可以在docker容器的 /etc/resolv.conf中找到
docker run -it --name test -p 192.168.30.70:5432:5432 redis
vim /etc/docker/daemon.json
{
"bip":"10.0.0.1/16"
}
systemctl restart docker.service
[root@sx ~]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 10.0.0.1 netmask 255.255.0.0 broadcast 10.0.255.255
ether 02:42:d8:a7:41:03 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.245.4 netmask 255.255.255.0 broadcast 192.168.245.255
inet6 fe80::d4f2:8d5f:bf2:dbf0 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:90:e6:8d txqueuelen 1000 (Ethernet)
RX packets 452 bytes 43605 (42.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 317 bytes 50079 (48.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
开启container1
docker run -it --name net1 --rm busybox
开启container2 并把ip挂到net1上面
docker run -it --name net2 --network container:net1 --rm busybox
docker run -it --name net3 --network host --rm busybox
在network中 和 在宿主机中的 ifconfig内容相同 代表连接到了同一块网卡上 这种方式比桥接暴露端口的好处是可以减少一次nat转换,提高访问效率
docker run -it -v /host/data/valume1:/data --name valume1 -rm busybox
docker run -it -v /host/data/valume1:/data --name valume2 -rm busybox
docker run -it --volumers-from valume2 --name valume3 -rm busybox
要求
- 创建一个目录来存储相关文件和依赖
- DockerFile文件首字母大写
- 文件内容推荐大写
docker build原理
- docker commit:容器其实是在镜像之上联合挂在一个可写层,在在基于容器制作镜像的时候把可写层打包
- docker build: 基于DockerFile,其实也会私下启动一个容器,打包的也是镜像之上的可写层,只不过是对用户不可见得
#构建一个暴露80端口的镜像
docker build -t testimage:v1 ./
#启动镜像时,用8080端口绑定到暴露的80端口上面
docker run --name dockertest --rm -p8080:80 testimage:v1 /bin/httpd -f -h /root/web/html/
#查看容器的ip
docker inspect dockertest
#访问对应的端口
curl <容器的ip>:8080
run与cmd的区别
run和cmd的第一种命令格式 run/cmd command 是以"/bin/sh/ -c"来启动主进程,保留了shell特性,但主进程pid不再是1
第二种命令格式 run/cmd ["","",""] 是以内核来启动主进程,主进程pid为1,但无法保留shell的特性
容器中的主进程要保证pid为1,这样才能接收到docker stop等命令;同时要保证拥有重定向,管道等shell父进程的特性
但pid为1的进程是由内核启动的,将失去shell的特性;由shell启动保留了特性,但是主进程变成了shell
所以现在的问题是,如何让容器中的主进程的pid是1,同时又让主进程拥有shell的特性;采用的方法是 exec commond,用exec来顶替shell的位置,启动主进程
但是entrypoint可以被docker run后面的 --entrypoint + "command"给重新定义
容器的健康与否不能只通过主进程是否运行判断,比如主进程处于死循环,无法实现预期功能,则它是不健康的
修改运行的shell 为其他的shell,比如win下的power shell
定义docker容器停止的信号值
#安装docker-registry
yum install docker-registry
rpm -ql docker-distribution
#把要push的镜像打好标签
docker tag sunxu:v3 <docker-registry所在服务器ip/或hostname>:5000/myweb:v3
#修改push容器的docker-daemon的配置文件,把daemon的传输方式从https改成http
# 即"insecure-registries":["192.168.245.4:5000"]
vi /etc/docker/daemon.json
{
"bip":"10.0.0.1/16",
"insecure-registries":["192.168.245.4:5000"]
}
#push镜像
docker push <docker-registry所在服务器ip/或hostname>:5000/myweb:v3
#pull镜像
docker pull <docker-registry所在服务器ip/或hostname>:5000/myweb:v3
私有镜像的存储技术
提供交互性极好的前端界面以及以下特性
Harbor被打包在镜像中,但它的运行要依赖redis,mysql等存储工具,所以Harbor的整个安装过程,需要借助docker的单机编排工具docker compose;具体得安装方式可以访问harbor的托管平台github
docker run的时候 可以通过参数来限制cpu和memory的使用量 具体设置可以参考网上教程;
比如cpu可以设置进程的优先级,cpu核心数,和cpu最大占用率;
内存可以设置最大内存,并在此基础上设置swap memory的数量
以前京东主要跑在openstack上,现在谷歌是京东最大股东,百分之80的服务已经跑在了k8s上;
蚂蚁金服也主要跑在k8s上;
k8s把众多容器都抽象到一个主机上,并且实现自动扩容缩容,当CPU占用超过80%就进行自动扩容
- 自动装箱,自我修复,水平扩展,服务发现,负载均衡,自动发布和回滚
- 秘钥和配置管理,存储编排,批处理执行
- k8s集群在底层需要网络和存储,再底层是核心资源,网络和存储需要配置文件
- k8s之上需要容器的运行环境,以及存储容器的容器注册,同时还要有监控和日志
- 在容器的运行环境之上的是负载均衡,自动构建和自动发行
- openshift是在k8s之上封装的一套paas服务,开发人员只需要开发software即可
docker exec 是连接到正在运行的容器上,可以附带命令 docker attach 是标准输出连接到容器上的shell脚本上,ctrl + c 会退出,一般用在有/bin/bash的容器