Docker搭建前端开发环境

前言

项目地址

Github

Docker Game

  • 4:20起床,debug
  • 在google中搜索100条docker相关的post
  • 在社交软件的时间线上写道”fuck docker”
  • 看10本docker的书
  • 穿docker的T-shirt
  • 不跟任何人说你搞不定docker
  • 说出自己搞定docker的日期并接受它
  • 宣誓自己学会了docker
  • 最后砸烂你的电脑

NEVER TOUCH NON-LINUX DOCKER!


Docker简介

  1. Docker就是一个启动很快的“虚拟机”,它仅提供必要的功能,体积小;它能更充分利用宿主的资源。
  2. Docker原配“只有”linux。Mac和Win所谓的支持Docker归根到底是通过在虚拟机上安装linux系统,再在linux上安装docker。(这句话不完全正确,参见[解决方案与心路历程8]
  3. Docker三个基本概念:Registry注册中心,Image镜像,Container容器
    • Registry包含多个Repo(仓库)和Tag(标签),从Registry下载Image的方式是pull <仓库名>:<标签名>,如pull ubuntu:16.04
    • Image是一个静态概念,相当于面向对象中的类,类不能直接使用,需要实例化。
    • Container是一个动态概念,相当于面向对象中的实例化,启动镜像生成容器就是实例化类的过程。只有容器才能被用户使用。
  4. 使用Docker的容器Container,任何的操作和数据在退出或重启后不会保存,只能通过Volume(卷)的方式保存常驻文件并和宿主机共享文件。可以理解成网吧的电脑每次重启都自动还原系统,只有U盘里面的东西不会变。
  5. Docker的容器Container所做的任何修改都不会影响到Image。除非用commit命令,将修改提交,才能将修改应用到Image,类似git的管理方式。

一、 旧的开发环境及可能产生的问题

传统的前端开发环境搭建方式可能产生的问题主要有两点:

  1. 新同事、新电脑或重装系统后,开发环境的搭建显得很繁复。
  2. 每个前端开发人员可能由于操作系统的不同,开发环境版本及插件版本不同造成开发环境不统一。

早几年,大公司都会采用开发机和多用户的方式来统一开发环境。每个开发人员只需要一台显示器和外设,全部连接到中型或大型开发机上进行开发。这种方式经济成本较高,管理成本也高。而现在更提倡轻量管理。节约成本的前提下如何解决上述的两个问题?

二、 解决方案与心路历程

寻找一个优秀解决方案的过程向来是艰辛的,下面是我的心路历程:

  1. **思维导图[/vm]**:最初考虑用虚拟机的方式,每个开发人员安装虚拟机和统一的镜像文件,镜像包含了统一的开发环境,本地开发目录和虚拟机共享,即可在虚拟机中对开发目录进行操作。这种方式简单易行。缺陷主要是性能相对会降低,同时对虚拟机镜像的维护不方便。虚拟机镜像如同一个黑盒,历史维护记录,目录结构不清楚,很容易引起混乱,当前的维护人员不清楚之前的维护人员到底安装了哪些东西,如何配置的等等。

  2. **思维导图[/docker]**:虚拟机的方案被Pass之后,目光聚焦到Docker,如[简介1]所述,Docker的轻量和高性能值得一试。于是查找相关资料,看到《用 Docker 快速配置前端开发环境》一文,见[附录1]。文中主要提及两点:

    • 使用Docker的图形化工具Kitematic管理Docker并基础平台
    • 使用linux的samba共享文件夹操作工作目录
  3. **思维导图[/docker/docker toolbox]**:Kitematic是Docker的UI壳子,上文提及使用Docker Toolbox进行安装,Docker Toolbox是Docker官方开发的 Docker套装,里面有全套Docker环境,也有图形化工具 Kitematic。注意Docker Toolbox在win下仅支持win7 X64到win10,这里开始就是茫茫多的坑了。如下图所示,Docker Toolbox默认安装Docker Client和Docker Machine。什么是Docker Machine?

  4. **思维导图[/docker/docker toolbox/docker machine]**:弄懂Docker Machine,先要弄清楚什么是boot2docker,如[简介2]所述,Docker原生只支持linux,Docker的诞生基于linux的底层虚拟化技术。为了能在非linux系统运行Docker,boot2docker才诞生。boot2docker实际上就是打包一个Virtual Box或Vagrant虚拟机,在虚拟机上安装一个最小化linux,在linux上安装Docker,同时boot2docker负责将使用者本机的docker命令和虚拟机linux里面的docker“无缝”连接起来。这就是boot2docker。由于boot2docker非原生非官方,存在诸多bug,如早期boot2docker兼容docker命令不全,由于Virtual Box和Vagrant不稳定经常导致崩溃等等。2015年Docker官方发布了Docker Machine,它的实现原理和boot2docker基本一样,但它能更好的替代boot2docker。直到如今,很少再看到使用boot2docker了,而是使用官方的Docker Toolbox打包的Docker Machine。当然我们并不是再也见不到boot2docker,在Docker Toolbox安装后的目录里,我们还是能看到boot2docker.iso这个文件,也就是说Docker Machine最终安装在虚拟机里面的linux系统,还是boot2docker当初创建、发布并维护至今的linux最小系统的镜像文件。

  5. **思维导图[/docker/docker toolbox/docker machine/platform]**:如你所想,无论是boot2docker还是Docker Machine,都是在非linux环境搭建虚拟机,再在虚拟的linux中安装Docker。这就与[简介1]的特性相矛盾。事实如此,非linux的Docker几乎不会用于当正式的生产环境,多用于研究Docker技术。那么这条路要走到尽头了?win10的出现带来了一些曙光,微软官方称win10“兼容”Docker,而Windows Server2016 更是宣称支持原生Docker。win7、win10、server 2016,这三者对Docker的支持究竟有什么不同?

  6. **思维导图[/docker/docker toolbox/docker machine/platform/win10]**:在第4节中,介绍了早几年,win10还没发布,win又缺乏对Docker的支持,于是采用了boot2docker和Docker Machine来支持Docker。他们的原理是基于Virtual Box或Vagrant虚拟机。也说到Virtual Box或Vagrant的不稳定性带来的问题。自win8开始,操作系统自带Hyper-V虚拟机。至此,市面上三大虚拟机软件齐聚一堂。

    • Virtual Box开源免费、安装包小、相对不稳定
    • Hyper-V作为win自带软件,在win下最稳定,但对于图形界面渲染性能较差
    • VMware workstation商用、收费、各方面都不错

    由于VMware收费和商用的性质,所以boot2docker和Docker Machine官方发布都仅支持开源免费的Virtual Box,民间不少开发者制作了boot2docker和Docker Machine支持VMware workstation、Hyper-V乃至其他虚拟机的插件,这里不再过多叙述。Hyper-V在经历win8、win8.1的磨合后,新的版本无论兼容性、稳定性还是运行效率,都有了更好的提升。于是微软在win10里,可以直接将docker安装运行在Hyper-V中,并在操作系统中直接加入了本机和Hyper-V中的Docker通讯交互的功能。也就是说win10基于Hyper-V,实现了boot2docker或Docker Machine的功能,基于Hyper-V的Docker更稳定。但是,说到底,win10的Docker还是跑在虚拟机下啊!穿个马甲还不认识你了???

  7. **思维导图[/docker/docker toolbox/docker machine/platform/win10/hyperv]**:所以win10可以在docker官网直接下载docker安装包,同时win10也支持Docker Toolbox使用Docker Machine的方式(参见[解决方案与心路历程3])。这里需要提醒一下,win10支持两种安装Docker的方式,而在[解决方案与心路历程3]中也提到Kitematic是docker的一个可视化UI,两种Docker安装Kitematic的方式也不一样,具体可参考[附录2]。简述步骤如下:

    • Docker Toolbox安装包自带Kitematic,可勾选后安装
    • win10的Docker安装包,安装完成后可在任务栏右键Docker,下载并安装Kitematic

    既然win10的Docker比基于Virutal Box的Docker Machine性能更好,那么自然而然就想考虑使用win10的Docker。然而却遇到一些不符合实际环境的问题:

    • 团队中确实有一些开发人员仍在使用win7
    • Hyper-V和VMware workstation冲突。由于Hyper-V独占硬件虚拟化,所以不能和VMware workstation或Virtual Box共存,而VMware workstation却能和Virtual Box共存(可能会产生网络冲突情况,但可以解决)。

    [解决方案与心路历程6]中有提到Hyper-V的图形界面渲染性能比较差,再加上部分开发人员需要在虚拟机中安装其他windows系统进行兼容性调试测试,甚至安装“黑苹果”,这方面Hyper-V基本没法满足。还有些开发人员使用基于Virtual Box的安卓模拟器,Hyper-V也无法与之共存。所以在实际环境面前,基于Hyper-V的Docker基本走到头了。

  8. **思维导图[/docker/docker toolbox/docker machine/platform/server2016]**:win10的Docker方案被Pass后,接着[解决方案与心路历程5],看看Windows Server 2016的原生Docker是什么。[附录3]中,微软官方介绍了Windows Container。主要是说Windows Server 2016上安装Docker可以切换到Windows Container模式。这是一个怎样的功能?[简介2]中说道Docker原生只支持linux,这句话现在不一定对了。Windows Container让Docker可以直接跑在Windows Server 2016下,不需要依赖任何linux虚拟机。但是,但是,但是!Windows Container的Docker容器目前只能跑.net或.net core的应用。不能安装其他操作系统的镜像。哈?半成品?Pass!

  9. **思维导图[/docker/docker toolbox/kitematic]**:Docker在win平台的3种“生命形态”已经全部了解完了,根据实际环境,为了兼容win7和VMware workstation,只能选择回到Docker Toolbox,拥抱Docker Machine。[解决方案与心路历程2]以及[附录1]中提到使用Kitematic可以更方便的管理Docker。《用 Docker 快速配置前端开发环境》[附录1]一文中,介绍了使用Kitematic搭建前端开发环境的整个流程。但是文中也提到“Windows 的 Kitematic 有严重 bug,改动 Settings 下的任何选项都会导致所有配置项丢失”,该文自2016.8提出,至今(2017.6)仍存在这个Bug。不能用图形化界面配置,用Kitematic启动Docker后还要执行脚本甚至写Docker命令?我要这UI有何用?我要这界面又如何???还不如基于Docker Machine,直接写一个脚本,前端开发人员按顺序点,就可以使用。所以至此,彻底摒弃Kitematic,参考Docker Toolbox安装目录里面的start.sh,重写一个脚本,完成所有功能。同时,我开始怀疑使用Docker搭建开发环境还有没有意义,毕竟基于Virtual Box再安装Docker,已经失去了Docker的优势。

  10. **思维导图[/docker/docker toolbox/docker machine/image]**:《用 Docker 快速配置前端开发环境》[附录1]一文中,基于官方的centos或者ubuntu,提前搭建好前端的开发环境,commit后生成新的Image,提供给前端开发人员使用。这种方式与[解决方案与心路历程1]中提到的虚拟机镜像方式几乎一模一样,经过几番折腾,我已经对Docker搭建前端开发环境产生怀疑。非linux平台下,使用Docker本来就不存在性能优势,还存在镜像不透明会导致管理混乱的问题。这样算下来,还不如使用虚拟机。考虑再三,决定不再使用打包Image的方式,而是采用Dockerfile的方式生成镜像。这才是Docker的天生优势,也是我决定继续完成这个项目的唯一理由。Dockerfile可以理解成一个批处理,里面包含生成镜像的所有指令,build Dockerfile时,会顺序执行这些指令,最终将镜像生成出来。详细的说明可参考[附录4]。使用Dockerfile,能让维护人员清晰的看到镜像生成的过程,修改和管理起来就非常清晰了。

  11. **思维导图[/docker/docker toolbox/docker machine/volume]**:[简介4]提到Docker的容器不会保存数据,持久化数据需要通过Volume方式挂载。也举了一个形象的例子,网吧电脑和U盘,在这里Volume就是U盘。Volume的挂载规则如下:

    • 挂载方式为 -v [宿主机路径]:[Docker容器路径]。 这里得理解宿主机是谁?由于我们使用的Docker实际上安装在虚拟机上,也就是说这里的宿主机路径是Virtual Box中linux虚拟系统内的路径。
    • Docker容器的路径必须是绝对路径
    • 可以挂载多个Volume,也就是可以插多个U盘
    • 可以不指定宿主机路径,这时候会在宿主机的默认路径下自动生成对应的volume路径,如/var/lib/docker/volumes/XXX

    根据上面的规则,可以看出Docker中的持久化数据通过挂载Volume,实际上存在宿主机的文件夹中,实现了Docker和宿主据的资源共享。也就是说我们已经把前端开发环境封装在Docker的Image中了,但是项目的源码不能放在Docker中,只能通过Volume的方式挂载到Docker中。那么我们怎么实现在我们本机编辑项目代码,并在Docker中build呢?

    [解决方案与心路历程2]中也提到《用 Docker 快速配置前端开发环境》[附录1]一文,使用Samba来实现这一流程。Samba是linux环境下的文件共享技术,在制作Image时,安装samba,并做好配置,将挂载的volume文件夹共享出来,这时候我们在本机就可以通过//192.168.99.100/share的方式进入Docker的文件夹系统,实现与Docker的数据交互。这是一个正向思维:

    • 通过-v [宿主机路径]:[Docker容器路径],先创建Docker的Volume
    • 在Docker中安装samba,将Volume共享出来
    • 在本机,通过读取网络共享文件夹的方式进入Docker的文件夹

    使用这种方法,数据其实是保存在宿主据路径,也就是linux虚拟机上。好处就是磁盘格式就是linux的磁盘格式。缺点也很明显,数据在虚拟机上,本机只是远程访问虚拟机数据而已。数据安全性很差,Virtual Box的稳定性大家都懂的,一旦虚拟系统奔溃或被误删。整个本地项目源码就没了!虽然我们可以通过git等工具上传,但容易丢失本地数据,这个也很致命!所以我们必须换一种方式,通过逆向思维:

    • 将本机的工作目录共享给Virtual Box 虚拟机
    • 再将Virtual Box 虚拟机中的这个目录挂载到Docker上

    这种方式,数据是保存在本机上的。好处当然是安全,缺点就是磁盘格式可能是windows下的NTFS,可能会产生一些问题。往下看,就踩坑了。

  12. **思维导图[/docker/docker toolbox/docker machine/volume/virtual box]**:为何要把本机目录共享给Virtual Box虚拟机?如下图所示,我们在安装好Docker Toolbox后,手动打开Virtual Box,查看名称为default的默认linux虚拟系统的配置。在共享文件夹一栏中可以看到,默认配置中,已经将本机C盘的User文件夹共享给linux虚拟系统。本机的其他目录并没有和虚拟机有连接。也就是说Docker通过Volume与宿主机共享文件,要想Docker和本机有数据交互,就先把本机目录共享给虚拟机(宿主机),再由虚拟机挂载到Docker上。

    通过手动挂载本机目录给Virtual Box,可以满足我的需求,但我更希望使用脚本的方式,自动完成这一工作,参考Virtual Box官方的文档,使用VBoxManage sharedfolder add命令可以实现脚本自动化挂载。详情参见[附录5]

  13. **思维导图[/docker/docker toolbox/docker machine/volume/virtual box/symlink]**:成功将本机目录与虚拟机中的Docker连接后,本以为万事大吉,不料却又是一个个大坑。在Docker中,切换到共享目录,对现有的前端项目使用npm install安装所需的module,提示报错Error: EROFS, read-only file system ...,经过查阅资料,原来是Virtual Box自4.1.8版本起,为了安全性,禁止在虚拟机挂载共享目录中创建symlink,此时可以继续使用VBoxManage命令来解决,VBoxManage setextradata VM_NAME(虚拟机名称) VBoxInternal2/SharedFoldersEnableSymlinksCreate/SHARE_NAME(共享文件夹名称) 1,详情见[附录6]

  14. **思维导图[/docker/docker toolbox/docker machine/volume/virtual box/ntfs]**:给虚拟机开启symlink后,继续遇到问题,仍提示symlink创建不成功,仔细想一下,NTFS是windows磁盘格式,它与linux的符号连接symlink本身就不一样,这个底层不兼容问题就是在[解决方案与心路历程11]中提到的又一个坑。再次查阅资料,通过第三方开源软件NTFS-3G挂载NTFS磁盘,可以使linux读写NTFS。但Virtual Box是虚拟机,没有物理磁盘一说,怎么挂载就成了问题。再考虑一下,既然linux中有NTFS-3G这类的软件支持NTFS,难道Virtual Box就没有想到?最终问题还是得到了解决,解决的方式很奇葩,用管理员权限打开Virtual Box就行了。详情见[附录7]

  15. **思维导图[/docker/docker toolbox/docker machine/volume/virtual box/uac]**:在[解决方案与心路历程12]中,我们使用了VBoxManage sharedfolder add命令来实现自动挂载本机目录给虚拟机,所以当初的设置是打开脚本,提示用户输入本机工作目录。为了方便,可以直接拖拽这个文件夹到控制台中。然而,为了使用管理员权限打开Virutal Box,我不得不把管理员权限挂到脚本上,然后就会产生一个老问题,拖拽文件夹的功能不能用了。这是因为脚本是管理员权限,而文件夹是用户权限,权限不同级,不能实现拖拽。具体原理可以参考我之前的一篇文章[附录8]。解决的方法只有三种:

    • win7可以直接使用管理员登陆,除了安全性较差,没其他问题。由于全局管理员权限,可以实现拖拽。
    • win8/8.1/10,也可以使用管理员登陆,也是安全问题。但还有一个问题,使用admin登陆后,不能使用Metro UI
      (Modern)里面的应用。
    • 放弃拖拽,手动输入路径,这里就需要注意,由于linux和windows磁盘目录管理方式不同,比如本机的工作路径是e:\workplace,那么在脚本的启动终端git bash中,对应的路径应该是/e/workplace
  16. **思维导图[/other]**:当然,整个过程遇到的坑并不仅是上述这些,再节选一部分问题和解决方案,说明如下:

    • 使用Kitematic时,启动卡在99%或100%的问题:我是手动删除Virtual Box里面的default虚拟系统,再重启解决。可以参考[附录9][附录10]
    • 在Docker中使用CentOS 7的systemctl提示权限不足或者提示Failed to get D-Bus connection: Operation not permitted的问题:Docker下的每种系统镜像基本都有坑,比如centos7就是这个问题,据说centos7.2会解决,但目前7.3仍是这个问题。解决方案见[附录11]
    • 在本机的git bash中使用-it与docker交互,提示the input device is not a TTY的问题:windows下使用sh可以通过git自带的git bash,windows在安装git时,可选择两种终端模式:

      默认使用MinTTY,在这种模式下,使用docker run -it XXX时,就会报上述错误。具体解决方案见[附录12]。要不就是重新安装git,更换终端模式为Windows' default,要不就是在执行交互模式的docker命令前加winpty,如winpty docker run -it XXX。为了统一起见,我在脚本启动docker容器并实现交互时,都在前面添加winpty

三、 项目简介(以Github最新Readme为准)#

项目地址

Github

基本功能:

基于Docker Toolbox,在start.sh的基础上实现了以下功能:

  1. 自动启动Docker Machine(Virtual Box)
  2. 设置本地工作目录,自动共享至虚拟机Docker Machine(Virtual Box)的/develop
  3. 基于centos:latest和自定义的Dockerfile一键安装前端开发环境
  4. 一键启动并进入前端开发环境
  5. 进入Docker Machine终端
  6. 重启Docker Machine

镜像的修改和安装软件如下:

  1. 使用centos:latest
  2. 替换yum源为163软件源
  3. 安装常用工具如curl、gcc等
  4. 安装nginx,初始版本为1.13.1
  5. 安装nodejs,初始版本为v6.11.0
  6. 安装cnpm
  7. 安装pm2工具

项目目录结构如下:

  • setup
    • DockerToolbox.exe
  • source
    • CentOS7-Base-163.repo
    • nginx.conf
    • nginx-1.13.1.tar.gz
    • node-v6.11.0-linux-x64.tar.xz
  • boot2docker.iso
  • centos.tar
  • docker_machine_shell.sh
  • Dockerfile
  • nginx_config.conf
  • start.bat

支持的操作系统:

win7 x64及以上

其他说明及限制:

  • 在BOIS中开启虚拟化技术
  • win8及以上需关闭Hyper-V
  • 默认只开启了Docker的80端口,其他端口不可访问,如需修改请参考“开发者文档”

综述:

由于项目使用Docker Machine在非linux环境下安装Docker,不能提现出Docker的秒级启动特性,同时由于Docker Machine基于Virtual Box,稳定性和综合性能都有所损耗。使用Dockerfile创建前端开发环境所需的镜像文件,使维护和管理更加清晰方便是唯一的优势。 所以该项目更多用于团队内学习和了解Docker的使用。

四、 使用者文档(以Github最新Readme为准)#

  1. 运行setup文件夹下的DockerToolbox.exe安装DockerToolbox。如果系统中已安装Virutal Box和Git,则不需要勾选,否则一定要注意勾选这两项。

  2. 运行start.bat,等待自动安装,直至出现如下的界面

  3. 输入1,回车,绿色文字提示输入工作目录。注意这里输入的是所有项目所在的文件夹。路径使用linux规范,如本机工作目录是e:\Repository,则应该输入/e/Repository。如果路径输入错误或路径不存在,则会提示,并要求重新输入。随后等待直至出现绿色文字提示Set Sharedfolder Success!。按回车继续。

  4. 输入2,回车,等待安装开发环境的镜像,直至出现绿色文字Setup Develop Dockerfile Sucess!。按回车继续。

  5. 输入3,回车,进入Docker容器,绿色文字提示WelCome to Docker! IP: 192.168.99.100,即为成功,使用这个IP就可以访问Docker。使用命令cd /develop,即可进入第3步中挂载的本地工作目录。注意,步骤1-4只需要执行一次,安装完成后,需要时只执行这一步骤即可进入Docker!除非需要更换工作目录,或更新、重装整个环境,按需要再次执行1-4步。

    • 通过cd命令进入所需的项目
    • 使用npm或cnpm install 必要的module
    • 根据实际要求编译或启动整个项目
    • 复制该Docker项目文件夹根目录的nginx_config.conf到工作目录的根目录,修改文件名为项目名称.conf(如e:\Repository\website.conf)
    • 编辑该文件,不要修改listen端口,修改server_name为所需的域名,修改location为本地nodejs服务路径。
    • 在控制台输入命令nginx -s reload,重启Docker中的nginx服务器,若无任何消息提示,则表示配置文件无误,重启完成。
    • 随后可在本机修改hosts文件,将nginx配置文件中填写的域名指向到Docker的IP。
    • 在本机浏览器输入域名,即可访问。
  6. 在控制台菜单输入4,即可进入Docker Machine的终端,一般用于维护,查看等进阶操作。

  7. 在控制台菜单输入5,可重启Docker Machine。某些时候重启以解决奔溃或者虚拟机异常等问题。

  8. 在控制台菜单输入6,退出控制台。

五 、 开发者文档(以Github最新Readme为准)#

维护建议说明:

  • 建议维护:代表建议开发者定期更新或修改
  • 一般维护:代表开发者无需频繁维护或可以对该文件不予理会
  • 不建议维护:代表不建议开发者修改该文件

维护文件:

  1. **[setup\DockerToolbox.exe]**(建议维护):可在docker官网下载,由于国内网络部分被墙,速度非常慢,需要ss或vpn访问。开发者可定期下载,更新替换项目中的DockerToolbox安装包。国内网络也可在代理网站下载

  2. **[source\CentOS7-Base-163.repo]**(一般维护):centos7的163yum源

  3. **[source\nginx-1.13.1.tar.gz]**(一般维护):nginx_1.13.1安装包

  4. **[source\node-v6.11.0-linux-x64.tar.xz]**(一般维护):nodejs_6.11.0安装包

  5. **[source\nginx.conf]**(一般维护):nginx配置,用于替换Docker中安装的nginx_1.13.1的默认配置文件。主要增加一行配置 include /develop/*.conf;,将/develop文件夹下的所有配置文件加载进来。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    #user  nobody;
    worker_processes 1;
    error_log logs/error.log;
    pid logs/nginx.pid;

    events {
    worker_connections 1024;
    }

    http {
    include mime.types;
    default_type application/octet-stream;
    access_log logs/access.log;
    sendfile on;
    keepalive_timeout 65;

    server {
    listen 80;
    server_name localhost;

    location / {
    root html;
    index index.html index.htm;
    }

    #error_page 404 /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root html;
    }
    }
    include /develop/*.conf;
    }

  6. **[boot2docker.iso]**(建议维护):boot2docker发布的用于安装docker的linux最小系统。Docker Toolbox安装后,目录中已经有boot2docker.iso文件,但有可能版本不是最新,启动Docker Machine时会检查对应的boot2docker.iso的版本,如果不是最新,会从github下载,还是国内网速影响,经常会失败。所以开发者可以定期通过ss或vpn下载新版的boot2docker.iso,启动脚本时,会自动将该目录的boot2docker.iso拷贝到Docker Machine中。

  7. **[centos.tar]**(不建议维护):制作的centos:latest 文件的导出包。如果需要更新最新的centos:latest版本,或者使用其他版本如centos:6.5。可以参考“使用者文档”,通过控制台选择4. Enter Docker Machine,进入Docker Machine终端:

    • 键入命令docker images 查看是否存在centos:latest镜像
    • 如果存在,键入命令docker rmi -f centos:latest删除现有的centos:latest
    • 键入命令docker pull centos:latestdocker pull centos:6.5下载最新的centos或指定版本的centos
    • 若下载非centos:latest,建议使用命令docker tag centos:6.5 centos:latest将其命名成latest,因为在[docker_machine_shell.sh]和[Dockerfile]中,很多指令基于centos:latest,以免引起不必要的麻烦。如果你很熟悉docker命令,可以修改[docker_machine_shell.sh]和[Dockerfile]的内容。
    • 键入命令docker save centos:latest > /e/centos.tar,就可以将centos:latest导出到E盘根目录,名称为centos.tar
  8. **[docker_machine_shell.sh]**(不建议维护):基于Docker Toolbox安装目录的start.sh修改的脚本。代码中凡是添加了##Custom Addition Begin标注的都是自定义的内容并配有注释,其他的均是Docker Toolbox的start.sh源码。部分自定义源码片段如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ##Custom Addition Begin
    #check docker toolbox
    if [ -z "${DOCKER_TOOLBOX_INSTALL_PATH}" ]; then
    echo "Docker ToolBox is not installed. Please re-run the Toolbox Installer and try again."
    read -p "Press enter to continue."
    exit
    fi
    cd "${DOCKER_TOOLBOX_INSTALL_PATH}"
    ##Custom Addition End
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    ##Custom Addition Begin
    #use local boot2docker.iso
    echo -e "${GREEN}Copy local boot2docker.iso... ${NC}"
    currentFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

    if [ ! -e "${currentFolder}/boot2docker.iso" ]; then
    echo -e "${GREEN}Can not find boot2docker.iso in ${currentFolder} ${NC}"
    else
    if [ ! -d "~/.docker/machine/cache" ]; then
    mkdir -p ~/.docker/machine/cache
    fi
    cp "${currentFolder}"/boot2docker.iso ~/.docker/machine/cache/
    fi
    ##Custom Addition End

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    ##Custom Addition Begin
    #Boot Manager
    STEP="Boot_Manager"

    Boot_Manager(){
    clear
    echo -e "${BLUE}-----Docker Machine Manager-----${NC}"
    echo -e "${BLUE}1. Set Sharedfolder ${NC}"
    echo -e "${BLUE}2. Setup Develop Environment ${NC}"
    echo -e "${BLUE}3. Enter Develop Environment ${NC}"
    echo -e "${BLUE}4. Enter Docker-Machine Bash ${NC}"
    echo -e "${BLUE}5. Restart Docker-Machine ${NC}"
    echo -e "${BLUE}6. Exit ${NC}"
    read choose
    case $choose in
    1) #1. Set Sharedfolder
    hasNoDir=true
    while ${hasNoDir}
    do
    echo -e "${GREEN}Input hostPath:${NC}"
    read hostPath
    hostPath=`echo $hostPath | sed "s/\"//g" | sed "s/'//g"`
    if [ -d "$hostPath" ]; then
    hasNoDir=false
    else
    hasNoDir=true
    echo -e "${GREEN}Can not find dir: ${hostPath} ${NC}"
    fi
    done
    if [ "${VM_STATUS}" == "Running" ]; then
    "${DOCKER_MACHINE}" stop "${VM}"
    fi
    #remove sharedfolder named develop
    "${VBOXMANAGE}" sharedfolder remove "${VM}" --name develop
    #add sharedfolder named develop
    "${VBOXMANAGE}" sharedfolder add "${VM}" --name develop --hostpath "${hostPath}" --automount
    #support symlink
    "${VBOXMANAGE}" setextradata "${VM}" VBoxInternal2/SharedFoldersEnableSymlinksCreate/develop 1
    #start vm
    "${DOCKER_MACHINE}" start "${VM}"
    yes | "${DOCKER_MACHINE}" regenerate-certs "${VM}"
    eval "$(${DOCKER_MACHINE} env --shell=bash --no-proxy ${VM})"
    echo -e "${GREEN}Set Sharedfolder Sucess! ${NC}"
    read -p "Press enter to continue."
    Boot_Manager
    ;;
    2) #2. Setup Develop Environment
    currentFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
    if [ ! -e "${currentFolder}/Dockerfile" ]; then
    echo -e "${GREEN}Can not find dockerfile in ${currentFolder} ${NC}"
    read -p "Press enter to continue."
    Boot_Manager
    fi
    if [ ! -e "${currentFolder}/centos.tar" ]; then
    echo -e "${GREEN}Can not find centos.tar in ${currentFolder} ${NC}"
    read -p "Press enter to continue."
    Boot_Manager
    fi

    #rm image named centos:latest
    docker rmi -f centos:latest || true
    #rm image named centos:heygears
    docker rmi -f centos:heygears || true
    #load image
    docker load < "${currentFolder}/centos.tar"
    #build dockerfile to generate centos:heygears
    cd "${currentFolder}"
    docker build --no-cache --rm -t centos:heygears .
    cd -
    echo -e "${GREEN}Setup Develop Dockerfile Sucess! ${NC}"
    read -p "Press enter to continue."
    Boot_Manager
    ;;
    3) #3. Enter Develop Environment
    #rm container named heygears
    docker rm -f `docker ps -a -f name=heygears -q` || true
    #run centos:heygears in docker machine
    #--privileged=true means run docker with the highest privileges
    #-p 80:80 means expose port 80
    #-v /develop:/develop means mount docker machine's path "/develop" to docker "/develop" based on setp 1(Set Sharedfolder)
    docker-machine ssh "${VM}" 'docker run -d --name heygears --privileged=true -p 80:80/tcp -v /develop:/develop centos:heygears'
    #show docker ip
    echo -e "${GREEN}WelCome to Docker! IP: `docker-machine ip` ${NC}"
    #use winpty enter container
    winpty docker exec -it heygears bash
    Boot_Manager
    ;;
    4) #4. Enter Bash
    cat << EOF
                        ##         .
                ## ## ##        ==
            ## ## ## ## ##    ===
        /"""""""""""""""""\___/ ===
    ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
        \______ o           __/
            \    \         __/
            \____\_______/

EOF
        echo -e "${BLUE}docker${NC} is configured to use the ${GREEN}${VM}${NC} machine with IP ${GREEN}$(${DOCKER_MACHINE} ip ${VM})${NC}"
        echo "For help getting started, check out the docs at https://docs.docker.com"
        echo


        docker () {
        MSYS_NO_PATHCONV=1 docker.exe "$@"
        }
        export -f docker

        if [ $# -eq 0 ]; then
        echo "Start interactive shell"
        exec "$BASH" --login -i
        else
        echo "Start shell with command"
        exec "$BASH" -c "$*"
        fi
        ;;
        5) #5. Restart Docker-Machine
        if [ "${VM_STATUS}" == "Running" ]; then
        "${DOCKER_MACHINE}" stop "${VM}"
        fi
        "${DOCKER_MACHINE}" start "${VM}"
        yes | "${DOCKER_MACHINE}" regenerate-certs "${VM}"
        eval "$(${DOCKER_MACHINE} env --shell=bash --no-proxy ${VM})"
        ;;
        6) #6. exit
        exit
        ;;
        *) #other operation
        Boot_Manager
        ;;
esac
}

Boot_Manager
##Custom Addition End
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

9. **[Dockerfile]**(建议维护):默认基于centos:latest,生成前端开发环境系统镜像的指令集。如需安装新版nginx或nodejs,执行其他系统命令,或安装其他软件,可以直接修改Dockerfile。使用者执行“使用者文档”步骤4,重新安装开发环境即可完成更新。

``` dockerfile
FROM centos:latest

MAINTAINER wurang

#复制本地yum源、nodejs安装包、nginx安装包
COPY source/CentOS7-Base-163.repo /etc/yum.repos.d
COPY source/node-v6.11.0-linux-x64.tar.xz /usr/local
COPY source/nginx-1.13.1.tar.gz /usr/local

#nodejs 环境变量
ENV PATH="/usr/local/node-v6.11.0-linux-x64/bin:$PATH"
#nginx 环境变量
ENV PATH="/usr/local/nginx/sbin:$PATH"

#支持库

#更新源、安装常用库、安装nginx、nodejs、cnpm、pm2、nginx
RUN cd /etc/yum.repos.d/ \
&& mv CentOS-Base.repo CentOS-Base.repo.bak \
&& mv CentOS7-Base-163.repo CentOS-Base.repo \
&& yum clean all \
&& yum makecache \
&& yum -y update \
&& yum -y install gcc-c++ \
&& yum -y install pcre pcre-devel \
&& yum -y install zlib zlib-devel \
&& yum -y install openssl openssl--devel \
&& yum -y install autoconf libjpeg libjpeg-devel libpng libpng-devel \
&& yum -y install freetype freetype-devel curl curl-devel libxml2 libxml2-devel \
&& yum -y install glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel \
&& cd /usr/local \
&& tar -zxvf nginx-1.13.1.tar.gz \
&& cd nginx-1.13.1 \
&& ./configure \
&& make \
&& make install \
&& cd /usr/local \
&& rm -rf /usr/local/nginx-1.13.1.tar.gz \
&& rm -rf /usr/local/nginx-1.13.1 \
&& xz -d node-v6.11.0-linux-x64.tar.xz \
&& tar -xvf node-v6.11.0-linux-x64.tar \
&& rm -rf node-v6.11.0-linux-x64.tar \
&& npm install -g cnpm --registry=https://registry.npm.taobao.org \
&& cnpm install -g pm2 \
&& yum clean all

#复制nginx配置
COPY /source/nginx.conf /usr/local/nginx/conf

CMD ["nginx", "-g", "daemon off;"]
  1. **[nginx_config.conf]**(一般维护):使用者基于该配置文件,在工作目录的根目录,为每一个项目配置nginx,通过代理,访问nodejs。

  2. **[start.bat](不建议维护):为了解决NTFS磁盘在Virtual Box共享目录以及linux下的种种问题,需使用管理员权限打开Virtual Box。于是在[docker_machine_shell.sh]**外,再包了一层批处理,自动使用windows管理员权限。

附录

  1. 用 Docker 快速配置前端开发环境
  2. Install Kitematic on Windows 10, 8, and 7 all Editions? GUI for Docker
  3. Windows Containers on Windows Server
  4. 使用 Dockerfile 定制镜像
  5. VBoxManage命令详解
  6. Creating symlinks in Virtual Box 4.1.8
  7. Correct way to setup Virtualbox 4.3 to use symlinks on guest
  8. 管理员权限打开VisualStudio无法访问网络磁盘的解决办法
  9. Stuck at 99%
  10. Windows 10 Starting Docker VM freezes @ 100%
  11. CentOS 7.2 Base Image Dockerfile with systemd Enabled
  12. Docker for Windows: Interactive Sessions in MinTTY Git Bash

Docker搭建前端开发环境

https://wurang.net/docker_frontend/

作者

Wu Rang

发布于

2017-06-14

更新于

2021-12-06

许可协议

评论