使用VirtualBox+Docker搭建可移植的Linux開發(fā)環(huán)境

目的

做過Linux開發(fā)的工程師可能都會或多或少有過如下的經(jīng)驗:

  • 需要至少兩臺開發(fā)機器,一臺Windows電腦用來運行IDE和各種工具,一臺Linux電腦用來做編譯和測試。
  • 兩臺機器同步代碼很麻煩??截惾菀壮霈F(xiàn)錯漏,samba共享又很慢(一個vimgrap運行半天)。
  • Linux機器下混雜著各種SDK,環(huán)境變量,臨時包,不知道什么版本的工程軟件……最后誰都不敢動這個神奇的環(huán)境,因為離開這個環(huán)境軟件就跑不起來,甚至編譯都編不過。
  • 測試團隊想復(fù)制你的環(huán)境,或者你想復(fù)制測試的環(huán)境來復(fù)現(xiàn)bug?辦不到……

這篇文章就是嘗試來解決這個問題的。

  • 首先,我們只需要一臺Windows電腦,并且宿主機和Linux環(huán)境共享數(shù)據(jù)。
  • 其次,它不慢,至少在主流的電腦配置上和你分開跑兩臺機器差不多。
  • 再次,這個環(huán)境可很容易的清理、復(fù)制、移植

這個方案不適合什么人

  • “老破小”(“老”電腦,“破”硬盤,“小”內(nèi)存)
  • Windows或Mac等非Linux環(huán)境的開發(fā)。或者桌面系統(tǒng)原本就是Linux。
  • 喜歡折騰vagrant的,對虛擬機有偏見特別是性能和穩(wěn)定性上的偏見的,或者開發(fā)環(huán)境很單純很簡單的。

對于直接上了docker Windows版的,可以忽略VirtualBox部分。Docker目前已經(jīng)原生支持Windows,但是有兩個條件:1是必須是Windows 10 Enterprise版本,Home版不帶hyper-v;2是必須打開hyper-v選項。
我之所以采用Virtualbox方案,是為了兼容Windows10 home版,以及關(guān)掉hyper-v。因為我需要跑的一個android虛擬機跟hyper-v沖突。

再說說vagrant。vagrant其實就是在虛擬機(比如VirtualBox)的基礎(chǔ)上再封裝了一層管理腳本,以及提供了許多預(yù)配置的虛擬機鏡像文件一個命令就可以下載+安裝+啟動。本身是很好的工具,批量部署很有優(yōu)勢,我也折騰過兩天。但個人感受有幾個缺點:比如引入了不必要的復(fù)雜性,比如幾個流行的Linux發(fā)行版的鏡像更新很不及時,比如自動化腳本出錯還得手動分析問題等等。因此放棄。

思路

方案的大體思路如下:

  • 首先宿主機器是一臺Windows。當然Mac甚至Linux也可以,但不在本文討論范疇。
  • 用免費的Oracle VirtualBox 搭建虛擬機,安裝Linux。
  • 把宿主機的一個目錄共享到虛擬機中,然后再用這個目錄創(chuàng)建一個所有容器共享的數(shù)據(jù)卷容器。以此在宿主機和各容器之間實現(xiàn)數(shù)據(jù)共享和同步。
  • 開發(fā)環(huán)境,版本管理環(huán)境,SDK環(huán)境,運行環(huán)境相互之間使用不同的容器將它們各自獨立。并且這些容器可以快速的部署到測試甚至生產(chǎn)環(huán)境。

組件圖

直接上圖


組件圖
  • 圖中只有一個角色,就是開發(fā)者了。
  • 這個角色有兩種主要用例,一是使用IDE等各種工具進行開發(fā),二是使用特定端口訪問運行環(huán)境的服務(wù)。在這里畫的是80端口的web服務(wù)。
  • 將Windows下目錄C:\foo\bar\workspace共享到虛擬機內(nèi)
  • 虛擬機掛載該共享目錄到/workspace
  • 使用docker創(chuàng)建一個workspace數(shù)據(jù)卷容器,卷掛載的是虛擬機系統(tǒng)的/workspace
  • 分別創(chuàng)建三個容器,包含運行環(huán)境,編譯環(huán)境,版本管理環(huán)境。這三個容器都把workspace容器卷作為數(shù)據(jù)卷。
  • 版本管理容器負責和遠端代碼倉庫同步代碼
  • 編譯環(huán)境負責把代碼編譯成可執(zhí)行程序
  • 運行環(huán)境負責運行可執(zhí)行程序
  • Docker會把運行環(huán)境的端口映射到虛擬機系統(tǒng)上
  • 由于虛擬機配置成網(wǎng)橋模式,所以宿主機可以直接訪問該端口

詳細步驟

安裝配置VirtualBox

安裝VirtualBox:先到官網(wǎng)下載最新版本的VirtualBox安裝包和擴展包,下載地址。這里需要注意的是,擴展包的版本必須和安裝包的版本一致。

安裝擴展包:雙擊安裝Virtualbox。裝好Virtualbox后,打開主界面,點擊:菜單->管理->全局設(shè)定->擴展->添加。然后選中擴展包。

下載Alpine Linux安裝盤: 下載地址。

這里多扯兩句。Linux發(fā)行版多如牛毛,最流行的莫過于Ubuntu和CentOS。這兩個發(fā)行版網(wǎng)上中英文資料,以及問題解答都很多,可能更適合初學者選擇。我之所以選用AlpineLinux,是因為其輕量化的特點。有專門為虛擬機優(yōu)化的版本,內(nèi)核經(jīng)過裁剪,安裝盤只有幾十MB。全部安裝完不到300MB磁盤占用。啟動也很快,占用資源少,在虛擬機中后臺運行基本無感。我們基本上所有“功能”都基于Docker搭建,所以Linux宿主系統(tǒng)并不需要任何額外的功能,只要把Docker跑起來即可。另外,AlpineLinux是docker官方御用操作系統(tǒng),很多鏡像文件都基于Alpine構(gòu)建。雖然宿主系統(tǒng)和鏡像系統(tǒng)之間并無太多聯(lián)系,但在學習曲線和操作習慣上,如果兩者統(tǒng)一,效率會有有所提高。

另外提一下,目前Docker的宿主系統(tǒng)中,CoreOS也是一個很好的選擇。CoreOS是專門為Docker量身打造的操作系統(tǒng),擁有許多優(yōu)秀特性。目前阿里云也支持該系統(tǒng)。有興趣可以了解一下。

新建虛擬機:在VirtualBox新建一個虛擬機,類型選擇“Linux 2.6 / 3.x / 4.x (64-bit)”。然后創(chuàng)建一個動態(tài)擴展的硬盤,大小可以選擇100G,反正是動態(tài)擴展。創(chuàng)建完成后,手動修改如下選項:

  • 使能PAE/NX
  • 使能硬件加速
  • 網(wǎng)卡配置成“橋接網(wǎng)卡”
  • USB設(shè)置成3.0版本
  • 共享文件夾添加一個工作目錄:C:\foo\bar\workspace,名稱設(shè)為“workspace”
  • 光驅(qū)選擇iso文件,然后找到我們剛才下載的AlpineLinux的iso

之所以選擇基于“Linux 2.6 / 3.x / 4.x (64-bit)”進行配置,是因為VirtualBox沒有默認的AlpineLinux的配置,而這個選項比較接近我們希望的配置。如果選擇的是“Other Linux”,VirtualBox會給出一個老舊機型的配置。

網(wǎng)卡配置成“橋接網(wǎng)卡”是為了虛擬機和外面的物理網(wǎng)絡(luò)能夠相互訪問。虛擬機能獲得物理網(wǎng)絡(luò)的IP。物理網(wǎng)絡(luò)中的設(shè)備(包括Windows宿主機)可以像訪問其他物理設(shè)備一樣訪問虛擬機(機器內(nèi)部的Docker,后面會說)。

這里選擇的共享文件夾,就是上面組件圖中的共享文件夾,用于在宿主機,虛擬機和Docker之間雙向共享數(shù)據(jù)用。

安裝AlpineLinux

  • 啟動虛擬機,用光盤啟動,然后用root登錄AlpineLinux,沒有密碼
  • 敲入命令
setup-alpine
  • 跟隨命令行向?qū)б徊揭徊綀?zhí)行
  • 在選擇安裝源時,敲入“f”讓系統(tǒng)自己尋找一個最快的源
  • 在選擇安裝目標盤時,敲入“sda”
  • 在選擇分區(qū)類型時,敲入“sys”
  • 幾分鐘就裝完了,退出光盤,重啟虛擬機

配置AlpineLinux

把網(wǎng)絡(luò)配置改成DHCP(非必須): 編輯/etc/network/interfaces,刪除eth0的固定IP配置,然后添加一行:

iface eth0 inet dhcp

配置打開軟件倉庫:編輯/etc/apk/repositories,把community源前面的注釋去掉。docker包是在community倉庫里面的,所以這步必須做。

升級系統(tǒng):執(zhí)行如下命令

apk update
apk upgrade

配置sshd:AlpineLinux默認是關(guān)閉root用戶ssh登錄的。最安全的做法是創(chuàng)建一個非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,并使其服務(wù)端隨系統(tǒng)啟動:

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

Docker國內(nèi)鏡像加速:創(chuàng)建一個文件/etc/docker/daemon.json,內(nèi)容為(如果有阿里云或者DaoCloud賬號,也可以配置成私有的加速鏈接):

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

搞定,重啟!

創(chuàng)建容器

下載鏡像

首先下載一個Alpine的基礎(chǔ)鏡像。行文時Alpine最新版本為3.8,建議按版本裝鏡像而不是拉latest,這樣以后好進行版本管理和遷移。

docker pull alpine:3.8

之所以再次選擇AlpineLinux作為容器的基礎(chǔ)鏡像,還是因為其輕量化。Alpine3.8的基礎(chǔ)鏡像僅為5MB!

創(chuàng)建數(shù)據(jù)卷容器

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

這個命令的意思是創(chuàng)建一個名字為workspace的容器,作為卷掛載本地(虛擬機Linux)的目錄/workspace到容器的/workspace目錄,使用alpine作為鏡像,鏡像版本3.8。那個大寫的Z在這里沒什么作用。但是如果虛擬機宿主Linux是CentOS這類啟用了SELinux的系統(tǒng),必須加這個參數(shù),要不然容器是無法讀寫這個目錄的!

創(chuàng)建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...]

創(chuàng)建SCM容器

這里以git為例。git是個很輕量級的工具,我們可以自己制作一個鏡像。
首先編寫Dockerfile,這個文件的作用就跟C/C++的Makefile差不多。類容如下:

FROM alpine:3.8
MAINTAINER Cary Tan tx-cary@163.com
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

然后執(zhí)行如下命令構(gòu)建并上傳鏡像到你的dockerhub。

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

用SCM鏡像創(chuàng)建一個容器去下載某項目的代碼:

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

創(chuàng)建RUN容器

RUN鏡像的環(huán)境根據(jù)項目不同,區(qū)別會很大。有時候可能還需要很多images/container一起協(xié)同工作。我在這里就舉一個最簡單的,用golang做的一個http hello world。

  1. 首先,在windows機器的workspace目錄下創(chuàng)建一個叫g(shù)ohttp的子目錄,然后創(chuàng)建一個原文件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鏡像創(chuàng)建容器進行編譯:
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鏡像創(chuàng)建一個運行容器,也即我們使用原始alpine鏡像作為我們的RUN鏡像:
docker run -it -p 80:80 --volumes-from workspace alpine:3.8 /workspace/bin/gohttp

以上關(guān)鍵參數(shù)是“-p 80:80”。意思是將容器內(nèi)的80端口映射到宿主機(虛擬機中的Linux系統(tǒng))上。
此時,順利的話,我們可以看到終端打印

Listening :80
  1. 最后,只需打開Windows上的瀏覽器,輸入虛擬機IP地址,就可以驗證我們的Hello World了!

自動啟動并登錄虛擬機

用過vagrant的都知道,這個工具最方便的地方就是只需要"vagrant up"和"vagrant ssh"兩條命令就可以自動啟動虛擬機并登錄進去。但我們也知道,vagrant其實就是基于Virtualbox命令行封裝的,所以我們只需要把關(guān)鍵命令找到,也可以在沒有vagrant的情況下實現(xiàn)類似的便捷。

我們得選擇一個趁手的終端軟件。我最喜歡的是MobaXTerm,并且是付費用戶。所以這里以MobaXTerm為例,直接使用cygwin,Win10自帶bash或ubuntu等應(yīng)該都能實現(xiàn)相同的功能。

新建一個Shell session,類型是“Bash”。在“Advanced Shell settings”中碼入如下腳本

/drives/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe startvm "alpine" --type headless
sleep 30
ssh -o ConnectTimeout=30 root@<IP addr>
/drives/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe controlvm alpine acpipowerbutton

保存,雙擊。這個腳本會自動啟動名為"alpine"的虛擬機,等待30秒,然后ssh登錄到虛擬機IP地址。當用戶退出ssh后,腳本自動關(guān)閉虛擬機。

安利一下MobaXTerm,這個終端軟件是基于cygwin的,功能十分強大。不僅支持SSH、Telnet、串口,還支持CMD,Powershell,bash等終端。甚至還支持VNC,F(xiàn)TP,SFTP,遠程桌面……不僅是客戶端軟件,它還內(nèi)置了各種服務(wù)器軟件,包括Xserver,TFTP,F(xiàn)TP,HTTP,SSH,Telnet,NFS,VNC……這款軟件大部分功能都是免費的,免費版的限制一個是session的數(shù)量有限制,二是各種server啟動時間有限制。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容