S2.9:多语言集合项目的容器实验
2020-01-10 本文已影响0人
睦月MTK
声明:所有的实验示例大部分来自《learn-docker-in-a-month-of-lunches》的作者Elton Stoneman,但运行结果并不都是照搬,大部分实验结果可能与原书不同
一、实验目的
- 为了加深对镜像创建与多阶段镜像创建的理解
- 为了验证不同类型的语言(Java、Node.JS、Go)在镜像创建上的流程是否一致
- 利用这个综合性实验加深对docker的理解
二、实验概述
- 实验的项目分别在ch04/exercises目录下的image-of-the-day、image-gallery、access-log三个子目录内
- access-log是一个Node.js编写的Web项目,由NPM进行包的管理,功能是提供一个被调用的接口,该接口被调用后,会记录传过来的日志信息,并在网页中显示日志数量
- image-of-the-day是一个由Java语言编写的,Spring Boot作为框架的Web项目,由Maven进行依赖管理,功能是在网页中显示从NASA获取的每日图片的各种信息,并调用access-log接口记录访问的网站
- image-gallery是一个由Go语言进行编写的Web项目,功能是调用image-of-the-day的接口获取图片信息,并将图片信息可视化展现出来
- Java、Node.js、Go这三种语言的执行过程差别很大。Java会先编译成Java字节码文件,然后由Java虚拟机进行运行。Node.Js是脚本类语言,可由解释器直接解释运行。Go语言会被先编译成对应平台的二进制文件,然后由对应平台自己执行。
三、实验预期效果
- 独立访问三个项目,结果均没有异常
- 访问image-gallery能够看到获取到的图片、标题等信息,然后刷新access-log页面,可以看到日志数量不为0
四、实验过程
- 创建docker虚拟网络(用于容器之间的互相访问,容器在该网络上的地址由Docker在创建容器时分配,该网络上的容器如果要访问另外一个同时也在网络上的容器,只需要使用另一个容器的容器名即可,指定某个容器加入某个虚拟网络使用--network选项就可以了)
$ docker network create nat
-
运行image-of-the-day项目
- 查看Dockerfile并分析
$ cd diamol/ch04/exercises/image-of-the-day $ cat Dockerfile FROM diamol/maven AS builder WORKDIR /usr/src/iotd COPY pom.xml . RUN mvn -B dependency:go-offline COPY . . RUN mvn package # app FROM diamol/openjdk WORKDIR /app COPY --from=builder /usr/src/iotd/target/iotd-service-0.1.0.jar . EXPOSE 80 ENTRYPOINT ["java", "-jar", "/app/iotd-service-0.1.0.jar"]
builder阶段使用的是diamol/maven镜像,里面包含Jdk以及Maven等工具,该阶段将项目打包成jar包供下个阶段使用
final[1]阶段使用的镜像只包含运行jar包的OpenJDK
- 生成镜像(生成过程较长,会包含springboot的日志和maven的日志,略去不写)
$ docker image build --tag image-of-the-day . $ docker image ls image-of-the-day REPOSITORY TAG IMAGE ID CREATED SIZE image-of-the-day latest c296340fbed8 46 hours ago 222MB
- 创建一个容器,命名为iotd,并加入虚拟网络nat,开放本机8080端口给容器的80
$ docker container run --name iotd --network nat --publish 8080:80 --detach image-of-the-day $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES aa960be5e7ae image-of-the-day "java -jar /app/iotd…" 31 seconds ago Up 30 seconds 0.0.0.0:8080->80/tcp iotd
- 浏览器访问
localhost:8080/image
查看结果
image-of-the-day
-
运行access-log项目
- 查看Dockerfile并分析
$ cd diamol/ch04/exercises/access-log $ cat Dockerfile FROM diamol/node AS builder WORKDIR /src COPY src/package.json . RUN npm install # app FROM diamol/node EXPOSE 80 CMD ["node", "server.js"] WORKDIR /app COPY --from=builder /src/node_modules/ /app/node_modules/ COPY src/ .
因为Js是一门解释性的语言,其实不存在编译阶段,但它需要NPM来进行包的的管理,
npm install
会下载所需的依赖到node_modules中,其实也可以进行分阶段(虽然我也觉得意义不大)- 生成镜像(略去镜像生成过程)
$ docker image build --tag access-log . $ docker image ls access-log REPOSITORY TAG IMAGE ID CREATED SIZE access-log latest eef7fdb72b9f 45 hours ago 88MB
- 创建一个容器,命名为accesslog,并加入虚拟网络nat,开放本机8081端口给容器的80
$ docker container run --name accesslog --network nat --publish 8081:80 --detach access-log $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 89ed197cffb8 access-log "docker-entrypoint.s…" 9 seconds ago Up 7 seconds 0.0.0.0:8081->80/tcp accesslog aa960be5e7ae image-of-the-day "java -jar /app/iotd…" 38 minutes ago Up 38 minutes 0.0.0.0:8080->80/tcp iotd
- 浏览器访问
http://localhost:8081/stats
查看结果
access-log
-
运行image-gallery项目
- 查看Dockerfile并分析
$ cd diamol/ch04/exercises/image-gallery $cat Dockerfile FROM diamol/golang AS builder COPY main.go . RUN go build -o /server # app FROM diamol/base ENV IMAGE_API_URL="http://iotd/image" \ ACCESS_API_URL="http://accesslog/access-log" CMD ["/web/server"] WORKDIR /web COPY index.html . COPY --from=builder /server . RUN chmod +x server
Go语言会被编译成所在平台对应的二进制文件,所以在final阶段其实只需要含有对应平台的系统就可以了,设置了两个环境变量
IMAGE_API_URL
和ACCESS_API_URL
用来指向前两个项目,RUN chmod +x server
用来设置在linux上的执行权限- 生成镜像(略去镜像生成过程)
$ docker image build --tag image-gallery . $ docker image ls image-gallery REPOSITORY TAG IMAGE ID CREATED SIZE image-gallery latest e2f1da18e564 45 hours ago 25.5MB
其实你会发现,经过多阶段生成的Go镜像极其的小
- 创建一个容器,加入虚拟网络nat,开放本机8082端口给容器的80
$ docker container run --network nat --publish 8082:80 --detach image-gallery $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ea3888ec096d image-gallery "/web/server" 12 seconds ago Up 11 seconds 0.0.0.0:8082->80/tcp jovial_cohen 89ed197cffb8 access-log "docker-entrypoint.s…" 21 minutes ago Up 21 minutes 0.0.0.0:8081->80/tcp accesslog aa960be5e7ae image-of-the-day "java -jar /app/iotd…" 59 minutes ago Up 59 minutes 0.0.0.0:8080->80/tcp iotd
- 浏览器访问
http://localhost:8082/
查看结果
image-gallery
五、实验结果
打开http://localhost:8082/
能看到图片,打开http://localhost:8081/stats
能看到logs不为0,实验达到预期结果
六、实验总结
虽然三种语言执行的流程大相径庭,但是都可以从中发现这么一些规律:
- 都将繁琐的编译,需要其他工具(final阶段不需要的)进行完成的任务放在了上一个阶段,只保留最简洁的部分给最终镜像,这也避免了潜在的攻击风险
- 三个项目都经历了创建镜像,创建容器这些流程,说明Docker的执行是具有标准流程的,这也确保了Docker良好的跨平台性与通用性
- 虽然容器之间是彼此独立的,但是容器可以通过多种方式去和外界沟通,甚至去和其他容器沟通
参考文档:
[1] learn-docker-in-a-month-of-lunches
[2] 官方文档
附:
[1] Elton Stoneman的github项目
-
没有特殊说明,final阶段均指最后一个阶段 ↩