容器化有什么好处?
1. 一致的运行环境
不会出现测试说有问题,然后开发说在机器上跑得好好的问题。
2. 持续交付
开发写完代码后,直接使用docker提交测试,测试完成之后就可以直接发布生产环境。而且非常简单方便,只需要把最新的镜像push上去
3. 易扩展,扩容缩容非常方便
swarm:docker service scale helloworld=5
kubernetes: kubectl scale deployment/helloworld replicas=5
4. 轻量级的隔离的运行环境
容器从进程级别隔离,且共享着同一个内核。也就是说容器内并没有一个完整的操作系统,它可以瞬间启动。开发者可以在开发机上无差别的启动几百个容器
一切以Linux、Windows为基础的运行程序都可以无差别的运行在容器中
只需要选择好对应的基础镜像即可,像Java应用一般会使用 Tomact、openJDK, .Net 则一般是 microsoft/aspnetcore
Dockerfile
Dockerfile是用于构建镜像的text文件,包含了构建该镜像所有必须的命令。
构建镜像大致包含如下步骤
1. 使用一个基础镜像
2. 指定应用工作目录
3. 将应用程序文件拷贝到容器中
4. 安装应用依赖包
5. 暴露应用端口
6. 设置环境变量
7. 设置容器启动时的执行命令
右图是一份构建python应用的Dockerfile
如何让构建后的应用更轻量、安全、占用资源少:
选择体积较小的基础镜像,如apline, 很多基础镜像都有apline版本
只拷贝应用相关的文件
清除安装应用依赖产生的缓存
如何使后期构建速度更快
应用文件分别拷贝,多写几个ADD命令,将变动较少的文件特别是定义安装依赖的文件放在最前,安装依赖后再拷贝其他文件,变动较快较多的文件放在后面。通常构建的时候安装依赖的耗时是最长的,如果依赖没有变动的话,直接可以利用之前构建的这一层
Java 应用容器化
以一个 Java web 应用为例,使用 tomcat 基础镜像,将打包好的 war 包 add 到 webapps 目录下,设置 正常启动 tomcat 的的命令即可。
注意:Java 应用最好在Dockerfile中设置堆内存大小限制环境变量(JAVA_OPTS, CATALINA_OPTS)。JVM 默认的垃圾回收阈值是宿主机内存的1/4,如果docker容器对内存有限制且小于宿主机内存的1/4,Java 应用可能会因为使用内存超出容器限制而被杀死。
微服务应用容器化
微服务有很多优点,但是也会带来相应挑战,微服务中最重要的就是服务发现。
单体式应用开发时很少提及服务发现,因为传统单体应用动态性不强,不会频繁的更新和重新发布,也较少进行自动伸缩。传统单体应用的网络位置很少发生变化,在发生变化时,由运维人员手工更新一下它们的配置文件,也不是什么太大的问题。
而微服务架构则完全不同,微服务会被频繁的更新和重新发布,频繁的根据负载情况进行动态伸缩,微服务实例还可能受资源调度影响而从一台服务器迁移到另一台服务器。
在微服务架构中,微服务实例的网络位置发生变化是一种常态,所以必须提供一种机制,使得服务消费者在服务提供者的网络位置发生变化时,能够及时获得最新的位置信息。
容器化之后这个事情就可以变得非常简单了,由外部框架来做这个事情。kubernetes就提供了Service来做服务发现. 微服务中服务的相互之间就可以通过service name来访问,不要知道服务的IP地址
右图为一个简单的2048应用,有5个实例,访问则直接通过Service访问,不用关心每个Pod的ip地址。
service通过selector找到相应的pod。
数据库容器化
1. 自己制作镜像
使用基础镜像,并安装需要的数据库。
缺点:
dockerfile 写起来比较麻烦
需要人工维护升级
2. 使用官方提供镜像
通常官方会给出几乎所有流行的、开源的数据库的 docker 镜像,并且由 docker 社区和该数据库的团队共同维护。像 mysql、mongodb、redis 等都有官方的镜像
调试容器化应用
1.构建运行
docker build & docker run
2.查看容器运行日志
docker logs <container_id>
kubectl logs <pod>
3.进入容器
docker exec -it <container_id> /bin/sh
kubectl exec -it <pod> /bin/sh
4.把容器文件拷出来
docker cp <container_id>:<file_path> ./