79

使用VirtualBox+Docker搭建可移植的Linux开发环境

 5 years ago
source link: https://studygolang.com/articles/13706?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

目的

做过Linux开发的工程师可能都会或多或少有过如下的经验:

  • 需要至少两台开发机器,一台Windows电脑用来运行IDE和各种工具,一台Linux电脑用来做编译和测试。
  • 两台机器同步代码很麻烦。拷贝容易出现错漏,samba共享又很慢(一个vimgrap运行半天)。
  • Linux机器下混杂着各种SDK,环境变量,临时包,不知道什么版本的工程软件……最后谁都不敢动这个神奇的环境,因为离开这个环境软件就跑不起来,甚至编译都编不过。
  • 测试团队想复制你的环境,或者你想复制测试的环境来复现bug?办不到……

这篇文章就是尝试来解决这个问题的。

  • 首先,我们只需要一台Windows电脑,并且宿主机和Linux环境共享数据。
  • 其次,它不慢,至少在主流的电脑配置上和你分开跑两台机器差不多。
  • 再次,这个环境可很容易的清理、复制、移植

这个方案不适合什么人

  • “老破小”(“老”电脑,“破”硬盘,“小”内存)
  • Windows或Mac等非Linux环境的开发。或者桌面系统原本就是Linux。
  • 喜欢折腾vagrant的,对虚拟机有偏见特别是性能和稳定性上的偏见的,或者开发环境很单纯很简单的。

对于直接上了docker Windows版的,可以忽略VirtualBox部分。Docker目前已经原生支持Windows,但是有两个条件:1是必须是Windows 10 Enterprise版本,Home版不带hyper-v;2是必须打开hyper-v选项。
我之所以采用Virtualbox方案,是为了兼容Windows10 home版,以及关掉hyper-v。因为我需要跑的一个android虚拟机跟hyper-v冲突。

再说说vagrant。vagrant其实就是在虚拟机(比如VirtualBox)的基础上再封装了一层管理脚本,以及提供了许多预配置的虚拟机镜像文件一个命令就可以下载+安装+启动。本身是很好的工具,批量部署很有优势,我也折腾过两天。但个人感受有几个缺点:比如引入了不必要的复杂性,比如几个流行的Linux发行版的镜像更新很不及时,比如自动化脚本出错还得手动分析问题等等。因此放弃。

思路

方案的大体思路如下:

  • 首先宿主机器是一台Windows。当然Mac甚至Linux也可以,但不在本文讨论范畴。
  • 用免费的Oracle VirtualBox 搭建虚拟机,安装Linux。
  • 把宿主机的一个目录共享到虚拟机中,然后再用这个目录创建一个所有容器共享的数据卷容器。以此在宿主机和各容器之间实现数据共享和同步。
  • 开发环境,版本管理环境,SDK环境,运行环境相互之间使用不同的容器将它们各自独立。并且这些容器可以快速的部署到测试甚至生产环境。

组件图

直接上图

ZjYzMj6.png!web

组件图

  • 图中只有一个角色,就是开发者了。
  • 这个角色有两种主要用例,一是使用IDE等各种工具进行开发,二是使用特定端口访问运行环境的服务。在这里画的是80端口的web服务。
  • 将Windows下目录C:\foo\bar\workspace共享到虚拟机内
  • 虚拟机挂载该共享目录到/workspace
  • 使用docker创建一个workspace数据卷容器,卷挂载的是虚拟机系统的/workspace
  • 分别创建三个容器,包含运行环境,编译环境,版本管理环境。这三个容器都把workspace容器卷作为数据卷。
  • 版本管理容器负责和远端代码仓库同步代码
  • 编译环境负责把代码编译成可执行程序
  • 运行环境负责运行可执行程序
  • Docker会把运行环境的端口映射到虚拟机系统上
  • 由于虚拟机配置成网桥模式,所以宿主机可以直接访问该端口

详细步骤

安装配置VirtualBox

安装VirtualBox:先到官网下载最新版本的VirtualBox安装包和扩展包, 下载地址 。这里需要注意的是,扩展包的版本必须和安装包的版本一致。

安装扩展包:双击安装Virtualbox。装好Virtualbox后,打开主界面,点击:菜单->管理->全局设定->扩展->添加。然后选中扩展包。

下载Alpine Linux安装盘: 下载地址

这里多扯两句。Linux发行版多如牛毛,最流行的莫过于Ubuntu和CentOS。这两个发行版网上中英文资料,以及问题解答都很多,可能更适合初学者选择。我之所以选用AlpineLinux,是因为其轻量化的特点。有专门为虚拟机优化的版本,内核经过裁剪,安装盘只有几十MB。全部安装完不到300MB磁盘占用。启动也很快,占用资源少,在虚拟机中后台运行基本无感。我们基本上所有“功能”都基于Docker搭建,所以Linux宿主系统并不需要任何额外的功能,只要把Docker跑起来即可。另外,AlpineLinux是docker官方御用操作系统,很多镜像文件都基于Alpine构建。虽然宿主系统和镜像系统之间并无太多联系,但在学习曲线和操作习惯上,如果两者统一,效率会有有所提高。

另外提一下,目前Docker的宿主系统中,CoreOS也是一个很好的选择。CoreOS是专门为Docker量身打造的操作系统,拥有许多优秀特性。目前阿里云也支持该系统。有兴趣可以了解一下。

新建虚拟机:在VirtualBox新建一个虚拟机,类型选择“Linux 2.6 / 3.x / 4.x (64-bit)”。然后创建一个动态扩展的硬盘,大小可以选择100G,反正是动态扩展。创建完成后,手动修改如下选项:

  • 使能PAE/NX
  • 使能硬件加速
  • 网卡配置成“桥接网卡”
  • USB设置成3.0版本
  • 共享文件夹添加一个工作目录:C:\foo\bar\workspace,名称设为“workspace”
  • 光驱选择iso文件,然后找到我们刚才下载的AlpineLinux的iso

之所以选择基于“Linux 2.6 / 3.x / 4.x (64-bit)”进行配置,是因为VirtualBox没有默认的AlpineLinux的配置,而这个选项比较接近我们希望的配置。如果选择的是“Other Linux”,VirtualBox会给出一个老旧机型的配置。

网卡配置成“桥接网卡”是为了虚拟机和外面的物理网络能够相互访问。虚拟机能获得物理网络的IP。物理网络中的设备(包括Windows宿主机)可以像访问其他物理设备一样访问虚拟机(机器内部的Docker,后面会说)。

这里选择的共享文件夹,就是上面组件图中的共享文件夹,用于在宿主机,虚拟机和Docker之间双向共享数据用。

安装AlpineLinux

  • 启动虚拟机,用光盘启动,然后用root登录AlpineLinux,没有密码
  • 敲入命令
setup-alpine
  • 跟随命令行向导一步一步执行
  • 在选择安装源时,敲入“f”让系统自己寻找一个最快的源
  • 在选择安装目标盘时,敲入“sda”
  • 在选择分区类型时,敲入“sys”
  • 几分钟就装完了,退出光盘,重启虚拟机

配置AlpineLinux

把网络配置改成DHCP(非必须): 编辑/etc/network/interfaces,删除eth0的固定IP配置,然后添加一行:

iface eth0 inet dhcp

配置打开软件仓库:编辑/etc/apk/repositories,把community源前面的注释去掉。docker包是在community仓库里面的,所以这步必须做。

升级系统:执行如下命令

apk update
apk upgrade

配置sshd:AlpineLinux默认是关闭root用户ssh登录的。最安全的做法是创建一个非root用户。懒人可以直接打开root登录。编辑/etc/ssh/sshd_config,加入一行:

PermitRootLogin yes

安装Virtualbox扩展包:这步是为了使AlpineLinux能够支持VirtualBox的共享目录。命令:

apk add virtualbox-guest-additions virtualbox-guest-modules-virt virtualbox-guest-modules-vanilla

启动挂载共享目录:这步是为了让AlpineLinux每次启动都自动挂载VirtualBox的共享目录。编辑/etc/fstab,加入一行

workspace /workspace vboxsf defaults 0 0

安装Docker:如下命令安装docker,并使其服务端随系统启动:

apk add docker
ln -s /etc/init.d/docker /etc/runlevels/default/docker

Docker国内镜像加速:创建一个文件/etc/docker/daemon.json,内容为(如果有阿里云或者DaoCloud账号,也可以配置成私有的加速链接):

{
"registry-mirrors": ["https://registry.docker-cn.com"]
}

搞定,重启!

创建容器

下载镜像

首先下载一个Alpine的基础镜像。行文时Alpine最新版本为3.8,建议按版本装镜像而不是拉latest,这样以后好进行版本管理和迁移。

docker pull alpine:3.8

之所以再次选择AlpineLinux作为容器的基础镜像,还是因为其轻量化。Alpine3.8的基础镜像仅为5MB!

创建数据卷容器

docker run -it --name=workspace -v /workspace:/workspace:Z alpine:3.8

这个命令的意思是创建一个名字为workspace的容器,作为卷挂载本地(虚拟机Linux)的目录/workspace到容器的/workspace目录,使用alpine作为镜像,镜像版本3.8。那个大写的Z在这里没什么作用。但是如果虚拟机宿主Linux是CentOS这类启用了SELinux的系统,必须加这个参数,要不然容器是无法读写这个目录的!

安装SDK镜像

这里以Golang为例,dockerhub上直接有官方的golang镜像,所以直接pull然后run即可

docker pull golang:1.10.3-alpine3.8
docker run -it --rm --volumes-from workspace golang:1.10.3-alpine3.8 [your commands...]

创建SCM镜像

这里以git为例。git是个很轻量级的工具,我们可以自己制作一个镜像。

首先编写Dockerfile,这个文件的作用就跟C/C++的Makefile差不多。类容如下:

FROM alpine:3.8
MAINTAINER Cary Tan [email protected]
ENV PS1='[git@docker $PWD]\$ '
RUN echo "http://mirrors.tuna.tsinghua.edu.cn/alpine/v3.8/main" > /etc/apk/repositories \
      && echo "http://mirrors.tuna.tsinghua.edu.cn/alpine/v3.8/community" >> /etc/apk/repositories \
      && apk update \
      && apk add git git-doc \
      && mkdir -p /workspace
WORKDIR /workspace
CMD /bin/sh

然后执行如下命令构建并上传镜像到你的dockerhub。

docker build -t <your_name>/git:<tag> /path/to/your/Dockerfile/
docker push <your_name>/git:<tag>

运行SCM镜像去下载某项目的代码:

docker run -it --rm --volumes-from workspace <your_name>/git:<tag> git clone ...

创建RUN镜像

RUN镜像的环境根据项目不同,区别会很大。有时候可能还需要很多images/container一起协同工作。我在这里就举一个最简单的,用golang做的一个http hello world。

  1. 首先,在windows机器的workspace目录下创建一个叫gohttp的子目录,然后创建一个原文件main.go。源码如下:
package main
import (
  "fmt"
  "net/http"
)

const (
  host string = ":80"
)

func main() {
  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello world!")
  })

  fmt.Println("Listening ", host)
  http.ListenAndServe(host, nil)
}
  1. 然后用golang的SDK镜像进行编译:
docker run -it --rm --volumes-from workspace golang:1.10.3-alpine3.8 go build -o /workspace/bin/gohttp /workspace/gohtt
p/main.go
  1. 用alpine镜像创建一个运行容器。也即我们使用原始alpine镜像作为我们的RUN镜像:
docker run -it -p 80:80 --volumes-from workspace alpine:3.8 /workspace/bin/gohttp

以上关键参数是“-p 80:80”。意思是将容器内的80端口映射到宿主机(虚拟机中的Linux系统)上。

此时,顺利的话,我们可以看到终端打印

Listening :80
  1. 最后,只需打开Windows上的浏览器,输入虚拟机IP地址,就可以验证我们的Hello World了!

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK