[关闭]
@lijianying10 2015-06-03T13:41:19.000000Z 字数 3785 阅读 1789

构建最小Docker Image运行网站程序并部署到DaoCloud中

title: 构建最小Docker Image运行网站程序并部署到DaoCloud中
date: 2015-06-02 23:54:38
categories: 技术

[DaoCloud,Docker,Linux,Ubuntu,BusyBox,Golang]

意义:

在前人的工作中:创建尽可能小的Docker容器中文翻译版本。经过对比我们可以发现 Adriaan de Jonge的的工作方式是通过CGO实现golang的静态编译以达到目的。我们认为这种方式虽然很棒,但是操作起来并不容易,而且在很多项目中编译起来颇为麻烦。

基于原来的不足,或者说是太专注的人过于追求极致,我们在极致精简与正常使用操作系统(比如说基于ubuntu14.04)做工程角度的平衡,我们还是基于Scratch空Docker image进行构建,使用busybox重新构建了一个大小为5MB左右裁剪过的Linux作为golang运行环境,该系统可以直接使用普通golang编译器输出amd64架构的程序,整个image构建完成之后大小为11.75mb。在DaoCloud中可以达到秒级构建,经过4次测试3次在一分钟以下最短45秒。

Dockerfile以及环境参考:https://github.com/lijianying10/DaoCloudStaticBlog

golang HTTP 主程序

  1. package main
  2. import "net/http"
  3. import "fmt"
  4. func main() {
  5. fmt.Println("Server start") //最简单的日志提示已经开始工作
  6. http.Handle("/",http.FileServer(http.Dir("/public/"))) // 设置静态文件路由
  7. http.ListenAndServe(":8080", nil)// 开始http server
  8. }

Golang给出了足够多的Web开发工具包,可以编写简短的代码写出高性能web静态服务器。

Docker image中底层系统的构建

如果方便使用ubuntu 14.04 amd64的情况下:

  1. apt-get install busybox-static #安装busybox
  2. mkdir /rootfs #新建根
  3. mkdir bin etc dev dev/pts lib proc sys tmp #根据根的格式创建目录
  4. touch etc/resolv.conf # DNS服务器地址
  5. cp /etc/nsswitch.conf etc/nsswitch.conf #名字解析配置
  6. echo root:x:0:0:root:/:/bin/sh > etc/passwd # 新建用户
  7. echo root:x:0: > etc/group #新建用户组
  8. ln -s lib lib64 # 创建软连接
  9. ln -s bin sbin
  10. cp /bin/busybox bin # 复制bin文件,不然没有命令用
  11. $(which busybox) --install -s bin #同上两步操作,用which是因为需要绝对路径
  12. bash -c "cp /lib/x86_64-linux-gnu/lib{c,m,dl,crypt,util,rt,nsl,nss_*,pthread,resolv}.so.* lib" # 这一步很重要,如果使用了Go调用外部动态库这里需要复制进去,
  13. bash -c "cp /lib/x86_64-linux-gnu/ld* lib" #同上
  14. cp /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 lib #同上
  15. tar cf /rootfs.tar . #根目录打包
  16. for X in console null ptmx random stdin stdout stderr tty urandom zero ; do tar uf /rootfs.tar -C/ ./dev/$X ; done #复制设备,注意自己的程序调用的设备,比如说random,顺便吐槽一下等待cpu周期太长

构建调试过程中的注意事项:
1. 在复制lib文件夹的底层动态库的时候需要不断调试动态库的依赖。
2. 因为容器中要运行不同的项目,有可能对设备与权限上有不同的需求,需要注意定制脚本及时调整。
3. 整个打包过程每次项目几乎只需要一次,调整项目大部分情况都是增量打包因此精简系统文件尽量仔细做。

boot2Docker 跨平台解决方案的Dockerfile(仿造上面来):

  1. FROM ubuntu:14.04
  2. RUN apt-get update -q
  3. RUN apt-get install -qy busybox-static
  4. RUN mkdir /rootfs
  5. WORKDIR /rootfs
  6. RUN mkdir bin etc dev dev/pts lib proc sys tmp
  7. RUN touch etc/resolv.conf
  8. RUN cp /etc/nsswitch.conf etc/nsswitch.conf
  9. RUN echo root:x:0:0:root:/:/bin/sh > etc/passwd
  10. RUN echo root:x:0: > etc/group
  11. RUN ln -s lib lib64
  12. RUN ln -s bin sbin
  13. RUN cp /bin/busybox bin
  14. RUN $(which busybox) --install -s bin
  15. RUN bash -c "cp /lib/x86_64-linux-gnu/lib{c,m,dl,crypt,util,rt,nsl,nss_*,pthread,resolv}.so.* lib"
  16. RUN bash -c "cp /lib/x86_64-linux-gnu/ld* lib"
  17. RUN cp /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 lib
  18. RUN tar cf /rootfs.tar .
  19. RUN for X in console null ptmx random stdin stdout stderr tty urandom zero ; do tar uf /rootfs.tar -C/ ./dev/$X ; done

非安全快速解决方案

我们这里的安全性是指,我提供的tar根目录中也许包含了老版本的代码漏洞,或者各种技术债务。如果不是特殊场景下不需要自己手动构建Linux根。

具体解决方案如下:
1. 直接在Dockerhub上使用progrium/busybox
2. 直接使用我们在github上共享的rootfs.tar

方式1不是很推荐,因为构建的适合需要从网上下载依赖,可能会降低构建速度。
非安全情况下推荐方式2构建所需要的docker image

方式1构建的Dockerfile:

  1. FROM progrium/busybox
  2. MAINTAINER Jianying Li <lijianying12@gmail.com>
  3. RUN mkdir -p /app
  4. WORKDIR /app
  5. COPY ./static /app/
  6. COPY ./public /public
  7. EXPOSE 80
  8. CMD ["/app/static"]

方式2构建使用的Dockerfile:

  1. FROM scratch
  2. MAINTAINER Jianying Li <lijianying12@gmail.com>
  3. ADD ./rootfs.tar /
  4. RUN mkdir -p /app
  5. WORKDIR /app
  6. COPY ./static /app/
  7. COPY ./public /public
  8. EXPOSE 80
  9. CMD ["/app/static"]

Tip: static为第一节编译好的golang静态程序
public为静态网站根目录

Tip:在构建时请不要使用sudo docker build -< somefile
要使用sudo docker build .

Tip: 方式2是我在Github中提供的方式。

跨平台支持

在本方案中跨平台的支持主要有两个方面:
1. golang源程序的跨平台编译:GOX
2. busybox 系统根(方案二中的Dockerfile中的文件rootfs.tar)的编译可以通过boot2docker来实现。

DaoCloud部署

DaoCloud给我们提供了一个非常好的测试平台,验证性能工作方式等等,不需要电脑中有Docker环境也可测试非常方便。
在这里我们介绍一下上面提供的github仓库的使用方法。
1. Fork我们提供的代码仓库到您的github账号中。
2. 登陆到DaoCloud.io使用代码构建功能
3. 给项目取名字
4. 登陆到github中系统会列出您在Github中的所有项目。并选中DaoCloudStaticBlog项目点击开始创建

在这之后DaoCloud会帮您创建目标项目的DockerImage。
在镜像仓库中找到项目点击部署给容器起名选择环境即可运行。

注意事项
1. Golang程序中的端口一定要与Dockerfile中的EXPOSE的号码对应,不然外网无法从DaoCloud访问您的容器。
2. CMD中注意要直接运行网站。
3. 如果条件允许请在本地调试运行之后再部署到DaoCloud中。

总结

在本次工作中我们使用了BusyBox来替代原来CGO的实施方案,有效的解决了编译时的麻烦。建立了底层依赖后直接复制应用程序进入Docker image完成在DaoCloud上的部署。在Dockerfile的依赖上我们直接使用了scratch没有任何依赖,加快了构建的速度达到秒级构建。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注