├── Front-end_Docker.md ├── README.md ├── front-end-angular-advanced-api.md ├── front-end-angular-advanced-cdn.md ├── front-end-angular-advanced-optimize.md ├── front-end-angular-advanced.md ├── front-end-angular.md ├── front-end-deploy.md ├── front-end-express.md └── front-end-hello.md /Front-end_Docker.md: -------------------------------------------------------------------------------- 1 | # 前端开发者的 Docker 之旅 2 | 3 | ## 前端发展阶段 4 | >目标:描述近代前端的发展历程,引出前端部署问题 5 | 6 | ## 也许让运维也学学前端,那么天下就太平了 7 | >目标:定义 Docker 与前端的关系,介绍前端部署的几种方式,阐述 Docker 化的前端的优点所在 8 | 9 | [也许让运维也学学前端,那么天下就太平了](https://github.com/Ye-Ting/Develop/blob/master/front-end-deploy.md) 10 | 11 | ## Hello Docker 12 | > 目标:使用静态页面来完成一个简单的 Docker Demo 13 | 14 | [Hello Docker](https://github.com/Ye-Ting/Develop/blob/master/front-end-hello.md) 15 | 16 | ## Node Express Docker 17 | > 目标: 用 Docker 镜像的方式搭建 Node Express 应用 18 | 19 | [Node Express Docker](https://github.com/Ye-Ting/Develop/blob/master/front-end-express.md) 20 | 21 | ## Angular Docker 22 | > 目标:用 Docker 镜像的方式搭建 Angular 前端应用 23 | 24 | [Angular Docker](https://github.com/Ye-Ting/Develop/blob/master/front-end-angular.md) 25 | 26 | ## Angular Docker Advanced 27 | > 目标:Angular 前端应用的 Docker 实践技巧 28 | 29 | [Angular Docker Advanced](https://github.com/Ye-Ting/Develop/blob/master/front-end-angular-advanced.md) 30 | 31 | 本篇为个人原创,转载请联系 me@yeting.info -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 文档管理体系 2 | 3 | * Github 文档储存 4 | * Mou 文档编写 5 | * Marboo 文档管理 6 | 7 | -------------------------------------------------------------------------------- /front-end-angular-advanced-api.md: -------------------------------------------------------------------------------- 1 | ### Angular 应用根据环境变量切换不同的后端 API 2 | 3 | 在 Angular 项目在实际运用中,我们的项目需要根据不同的开发要求,对接不同后端 API 4 | 5 | 怎么通过单一的 Docker image 实现对接不同的后端API呢? 6 | 7 | 我们基于 [Angular Docker]() 来做一些改进。 8 | 9 | gulp 是一个很好用的构建工具,不紧是因为他的语法灵活,更是因为有非常多的插件我供我们使用。 10 | 11 | 在这个例子中使用 [gulp-ng-config](https://www.npmjs.com/package/gulp-ng-config) 12 | 13 | ### Angular 项目构建优化 14 | 15 | 首先,安装插件 `gulp-ng-config` 16 | 17 | ``` 18 | npm install gulp-ng-config --save-dev 19 | ``` 20 | 21 | 接着,我们在 `/gulp/env.js` 文件下编写相应的 Task 22 | 23 | ``` 24 | gulp.task('env:config', function () { 25 | var env = process.env.APP_ENV || 'local'; // 暴露 APP_ENV 环境变零 26 | 27 | return gulp.src( 28 | path.join(conf.paths.src, '/config.json') 29 | ) 30 | .pipe($.ngConfig('app.config', { 31 | environment: env 32 | })) 33 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/'))); 34 | 35 | }); 36 | ``` 37 | 38 | 并将 `env:config` task 加入到 `inject` task (`/gulp/inject.js:12`) 之前 39 | ``` 40 | gulp.task('inject', ['scripts', 'styles','env:config'], function () { ...}) 41 | ``` 42 | 43 | 然后,我们在 `/src/config.json` 文件下,不同的环境设置不同的 apiUrl 44 | 45 | ``` 46 | { 47 | "local": { 48 | "config": { 49 | "apiUrl": "http://api.angular-docker-sample.app/api/local" 50 | } 51 | }, 52 | "test": { 53 | "config": { 54 | "apiUrl": "http://api.angular-docker-sample.app/api/test" 55 | } 56 | }, 57 | "production": { 58 | "config": { 59 | "apiUrl": "http://api.angular-docker-sample.app/api/production" 60 | } 61 | } 62 | } 63 | 64 | ``` 65 | 66 | 最后,修改 `/src/index.module.js` 引入配置 module 67 | 68 | ``` 69 | (function() { 70 | 'use strict'; 71 | 72 | angular 73 | .module('angularDockerSample', [ 74 | // core 75 | 'app.config', // 这里是新添加的 76 | // vendor 77 | 'ngAnimate', 78 | 'ngCookies', 79 | 'ngTouch', 80 | 'ngSanitize', 81 | 'ngResource', 82 | 'ui.router', 83 | 'ui.bootstrap' 84 | ]); 85 | 86 | })(); 87 | ``` 88 | 89 | ### 构建 Docker Image 90 | 91 | 使用下面的 Dockerfile 92 | 93 | ``` 94 | FROM node:0.12.7-wheezy 95 | 96 | RUN apt-key adv --keyserver pgp.mit.edu --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 97 | RUN echo "deb http://nginx.org/packages/mainline/debian/ wheezy nginx" >> /etc/apt/sources.list 98 | 99 | ENV NGINX_VERSION 1.7.12-1~wheezy 100 | 101 | RUN apt-get update && \ 102 | apt-get install -y ca-certificates nginx && \ 103 | rm -rf /var/lib/apt/lists/* 104 | 105 | # forward request and error logs to docker log collector 106 | RUN ln -sf /dev/stdout /var/log/nginx/access.log 107 | RUN ln -sf /dev/stderr /var/log/nginx/error.log 108 | 109 | EXPOSE 80 110 | 111 | RUN npm install -g bower gulp 112 | 113 | WORKDIR /app 114 | 115 | COPY ./package.json /app/ 116 | COPY ./bower.json /app/ 117 | RUN npm install && bower install --allow-root 118 | 119 | COPY . /app/ 120 | 121 | CMD gulp build && cp -r dist/* /usr/share/nginx/html/ && nginx -g 'daemon off;' 122 | ``` 123 | 124 | 有了 Dockerfile 以后,我们可以运行下面的命令构建前端镜像并命名为 my-angular-api-app: 125 | 126 | ```bash 127 | docker build -t my-angular-api-app . 128 | ``` 129 | 130 | ### 部署 Docker Image 131 | 132 | 最后,让我们从镜像启动容器: 133 | 134 | ``` 135 | docker run -p 80:80 -e "APP_ENV=production" my-angular-api-app 136 | ``` 137 | 138 | 这样子我们就能从 80 端口去访问我们的 Angular 应用,并且该 Angular 应用是对应着不同的 apiUrl。 -------------------------------------------------------------------------------- /front-end-angular-advanced-cdn.md: -------------------------------------------------------------------------------- 1 | ###Angular 应用根据环境变量切换不同的 CDN 2 | 3 | 在 Angular 项目在实际运用中,我们需要静态文件放在 CDN 上 4 | 5 | 怎么通过单一的 Docker image 实现 CDN 地址可变呢? 6 | 7 | 我们基于 [Angular Docker]() 来做一些改进。 8 | 9 | gulp 是一个很好用的构建工具,不紧是因为他的语法灵活,更是因为有非常多的插件我供我们使用。 10 | 11 | 在这个例子中使用 [gulp-cdnizer](https://www.npmjs.com/package/gulp-cdnizer) 12 | 13 | ### Angular 项目构建优化 14 | 15 | 首先,安装插件 `gulp-cdnizer` 16 | 17 | ``` 18 | npm install gulp-ng-config --save-dev 19 | ``` 20 | 21 | 接着,我们在 `/gulp/env.js` 文件下编写相应的 Task 22 | 23 | ``` 24 | gulp.task('cdn', function () { 25 | 26 | var cdn = process.env.APP_CDN || ''; 27 | 28 | return gulp.src( 29 | path.join(conf.paths.dist, '*.html') 30 | ) 31 | .pipe($.cdnizer({ 32 | defaultCDNBase: cdn, 33 | files : [ 34 | 'scripts/*.js', 35 | 'styles/*.css' 36 | ] 37 | })) 38 | .pipe(gulp.dest( 39 | path.join(conf.paths.dist) 40 | )); 41 | }); 42 | 43 | ``` 44 | 45 | ### 构建 Docker Image 46 | 47 | 对 Dockerfile 启动命令 CMD 进行细微的调整。 48 | 49 | ``` 50 | FROM node:0.12.7-wheezy 51 | 52 | RUN apt-key adv --keyserver pgp.mit.edu --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 53 | RUN echo "deb http://nginx.org/packages/mainline/debian/ wheezy nginx" >> /etc/apt/sources.list 54 | 55 | ENV NGINX_VERSION 1.7.12-1~wheezy 56 | 57 | RUN apt-get update && \ 58 | apt-get install -y ca-certificates nginx && \ 59 | rm -rf /var/lib/apt/lists/* 60 | 61 | # forward request and error logs to docker log collector 62 | RUN ln -sf /dev/stdout /var/log/nginx/access.log 63 | RUN ln -sf /dev/stderr /var/log/nginx/error.log 64 | 65 | EXPOSE 80 66 | 67 | RUN npm install -g bower gulp 68 | 69 | WORKDIR /app 70 | 71 | COPY ./package.json /app/ 72 | COPY ./bower.json /app/ 73 | RUN npm install && bower install --allow-root 74 | 75 | COPY . /app/ 76 | 77 | CMD gulp build && gulp cdn && cp -r dist/* /usr/share/nginx/html/ && nginx -g 'daemon off;' 78 | ``` 79 | 80 | 有了 Dockerfile 以后,我们可以运行下面的命令构建前端镜像并命名为 my-angular-cdn-app: 81 | 82 | ```bash 83 | docker build -t my-angular-cdn-app . 84 | ``` 85 | 86 | ### 部署 Docker Image 87 | 88 | 最后,让我们从镜像启动容器: 89 | 90 | ``` 91 | docker run -p 80:80 -e "APP_CDN=这里填写你自己的CDN" my-angular-cdn-app 92 | ``` 93 | 94 | 这样子我们就能从 80 端口去访问我们的 Angular 应用,并且该 Angular 应用是对应着不同的 cdn -------------------------------------------------------------------------------- /front-end-angular-advanced-optimize.md: -------------------------------------------------------------------------------- 1 | ###Angular 应用 Docker 启动加速 2 | 3 | 在 Angular 项目在实际运用中,我们的项目需要根据不同的开发要求,对接不同后端 API 4 | 5 | 怎么通过单一的 Docker image 实现对接不同的后端API呢? 6 | 7 | 这里我们给出了答案 : [Angular 应用根据环境变量切换不同的后端 API]() 8 | 9 | 但是这样做导致了 Docker 启动时要经过一段时间的前端项目的构建,牺牲了 Docker 秒级启动的特性 10 | 11 | 针对此,我们继续对这个流程进行优化。做到 Docker 秒级启动。 12 | 13 | 思路很简单,就是把耗时的事情,放在 Docker Build 的时候做。 14 | 15 | ### Angular 项目构建优化 16 | 17 | 首先,我们对 `/src/config.json` 文件,添加了 `needReplace` 18 | 19 | ``` 20 | { 21 | "local": { 22 | "config": { 23 | "apiUrl": "http://api.angular-docker-sample.app/api/local" 24 | } 25 | }, 26 | "test": { 27 | "config": { 28 | "apiUrl": "http://api.angular-docker-sample.app/api/test" 29 | } 30 | }, 31 | "production": { 32 | "config": { 33 | "apiUrl": "http://api.angular-docker-sample.app/api/production" 34 | } 35 | }, 36 | "needReplace": { 37 | "config": { 38 | "apiUrl": "THIS_IS_API_URL_NEED_REPLACE" 39 | } 40 | } 41 | } 42 | ``` 43 | 44 | 接着,我们修改 `/gulp/env.js` 文件,将 `env:config` 默认配置设置成 `needReplace` 45 | 46 | 添加 `env:replace` task ,将 `cdn` task 作为前置条件 47 | 48 | ``` 49 | gulp.task('env:config', function () { 50 | var env = process.env.APP_ENV || 'needReplace'; // 修改了这里 51 | 52 | return gulp.src( 53 | path.join(conf.paths.src, '/config.json') 54 | ) 55 | .pipe($.ngConfig('app.config', { 56 | environment: env 57 | })) 58 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/'))); 59 | 60 | }); 61 | 62 | gulp.task('env:replace', ['cdn'], function () { 63 | var envConfig = jsonfile.readFileSync(path.join(conf.paths.src, 64 | '/config.json')); 65 | var needReplace = envConfig.needReplace; 66 | var env = process.env.APP_ENV || 'local'; 67 | 68 | var stream = gulp.src( 69 | path.join(conf.paths.dist, '/scripts/*.js') 70 | ); 71 | for (var key in needReplace.config) { 72 | stream = stream.pipe( 73 | $.replace( 74 | needReplace.config[key], 75 | envConfig[env]['config'][key]) 76 | ); 77 | console.log(key, needReplace.config[key]); 78 | console.log(key, envConfig[env]['config'][key]); 79 | } 80 | 81 | return stream.pipe(gulp.dest(path.join(conf.paths.dist, '/scripts'))); 82 | 83 | }); 84 | ``` 85 | 86 | ### 构建 Docker Image 87 | 88 | Dockerfile 89 | 90 | ``` 91 | 92 | FROM node:0.12.7-wheezy 93 | 94 | RUN apt-key adv --keyserver pgp.mit.edu --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 95 | RUN echo "deb http://nginx.org/packages/mainline/debian/ wheezy nginx" >> /etc/apt/sources.list 96 | 97 | ENV NGINX_VERSION 1.7.12-1~wheezy 98 | 99 | RUN apt-get update && \ 100 | apt-get install -y ca-certificates nginx && \ 101 | rm -rf /var/lib/apt/lists/* 102 | 103 | # forward request and error logs to docker log collector 104 | RUN ln -sf /dev/stdout /var/log/nginx/access.log 105 | RUN ln -sf /dev/stderr /var/log/nginx/error.log 106 | 107 | EXPOSE 80 108 | 109 | RUN npm install -g bower gulp 110 | 111 | WORKDIR /app 112 | 113 | COPY ./package.json /app/ 114 | COPY ./bower.json /app/ 115 | RUN npm install && bower install --allow-root 116 | 117 | COPY . /app/ 118 | 119 | RUN gulp build 120 | 121 | CMD gulp env:replace && cp -r dist/* /usr/share/nginx/html/ && nginx -g 'daemon off;' 122 | ``` 123 | 124 | 有了 Dockerfile 以后,我们可以运行下面的命令构建前端镜像并命名为 my-angular-app: 125 | 126 | ```bash 127 | docker build -t my-angular-app . 128 | ``` 129 | 130 | ### 部署 Docker Image 131 | 132 | 最后,让我们从镜像启动容器: 133 | 134 | ``` 135 | docker run -p 80:80 -e "APP_ENV=production" my-angular-app 136 | ``` 137 | 138 | 这样的我们的 Angular 项目的启动速度就达到了秒级。 139 | -------------------------------------------------------------------------------- /front-end-angular-advanced.md: -------------------------------------------------------------------------------- 1 | ## Angular Docker Advanced 2 | > 目标:Angular 前端应用的 Docker 实践技巧 3 | 4 | 1. Angular 应用根据环境变量切换不同的后端 API 5 | 2. Angular 应用根据环境变量切换不同的 CDN 6 | 3. Angular 应用 Docker 启动加速 7 | 8 | 本项目代码维护在 [angular-docker-sample](https://github.com/Ye-Ting/angular-docker-sample) 9 | 10 | 引入 Docker 之后我们的前端构建过程也需要做相应的变化,那就是基于环境变量, 11 | 下面我基于在做 Angular Docker 之初遇到的几个较为困难的问题做了一些讲解。 12 | 13 | ### Angular 应用根据环境变量切换不同的后端 API 14 | 15 | [Angular 应用根据环境变量切换不同的后端 API](https://github.com/Ye-Ting/Develop/blob/master/front-end-angular-advanced-api.md) 16 | 17 | ### Angular 应用根据环境变量切换不同的 CDN 18 | 19 | [Angular 应用根据环境变量切换不同的 CDN](https://github.com/Ye-Ting/Develop/blob/master/front-end-angular-advanced-cdn.md) 20 | 21 | ### Angular 应用 Docker 启动加速 22 | 23 | [Angular 应用 Docker 启动加速](https://github.com/Ye-Ting/Develop/blob/master/front-end-angular-advanced-optimize.md) 24 | 25 | > **历史有时候会打转,咋一看以为是回去了,实际上是螺旋转了一圈,站在了一个新的起点** 26 | 27 | ### 终极 Docker 构建调试 DaoCloud 28 | 29 | [完] 30 | -------------------------------------------------------------------------------- /front-end-angular.md: -------------------------------------------------------------------------------- 1 | ## Angular Docker 2 | > 目标:用 Docker 镜像的方式搭建 Angular 前端应用 3 | 4 | 本项目代码维护在 [angular-docker-sample](https://github.com/Ye-Ting/angular-docker-sample) 5 | 6 | ### Angular 应用搭建 7 | 8 | 首先,借助 [generator-gulp-angular](https://github.com/Swiip/generator-gulp-angular) 生成一个 Angular 应用 9 | 10 | 具体的操作大致是 11 | 12 | ``` 13 | npm install -g yo gulp bower 14 | 15 | npm install -g generator-gulp-angular 16 | 17 | yo gulp-angular 18 | ``` 19 | 20 | 值得注意的是: 21 | 22 | * 项目依赖 node bower gulp 23 | * 调试命令 gulp serve 24 | * 调试发布命令 gulp serve:dist 25 | * 构建命令 gulp build 26 | * 构建目录 /dist 27 | * 构建出来的是纯静态文件 28 | 29 | 该应用有个小问题,fonts 文件在 build 之后就不显示了,需要修改 `bower.json` 30 | 31 | ``` 32 | { 33 | "dependencies": { 34 | ..... 35 | }, 36 | "overrides": { 37 | "bootstrap-sass-official": { 38 | "main": [ 39 | "assets/stylesheets/_bootstrap.scss", 40 | "assets/fonts/bootstrap/glyphicons-halflings-regular.eot", 41 | "assets/fonts/bootstrap/glyphicons-halflings-regular.svg", 42 | "assets/fonts/bootstrap/glyphicons-halflings-regular.ttf", 43 | "assets/fonts/bootstrap/glyphicons-halflings-regular.woff", 44 | "assets/fonts/bootstrap/glyphicons-halflings-regular.woff2" 45 | ] 46 | } 47 | } 48 | } 49 | 50 | ``` 51 | 52 | ### Dockerfile 编写 53 | 54 | 首先,选择官方的 node 镜像作为项目的基础镜像。一般采用 node:0.12.7-wheezy ,不会缺少各种各样的东西 55 | 56 | ``` 57 | FROM node:0.12.7-wheezy 58 | 59 | MAINTAINER YeTing "me@yeting.info" 60 | ``` 61 | 62 | 其次,由于该项目生成是纯静态文件,我们需要 Nginx 来作为 Web 服务器 63 | 64 | ``` 65 | RUN apt-key adv --keyserver pgp.mit.edu --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 66 | RUN echo "deb http://nginx.org/packages/mainline/debian/ wheezy nginx" >> /etc/apt/sources.list 67 | 68 | ENV NGINX_VERSION 1.7.12-1~wheezy 69 | 70 | RUN apt-get update && \ 71 | apt-get install -y ca-certificates nginx && \ 72 | rm -rf /var/lib/apt/lists/* 73 | 74 | # forward request and error logs to docker log collector 75 | RUN ln -sf /dev/stdout /var/log/nginx/access.log 76 | RUN ln -sf /dev/stderr /var/log/nginx/error.log 77 | 78 | EXPOSE 80 79 | ``` 80 | 81 | * Web 根目录 `/usr/share/nginx/html` 82 | * 访问日志输出到了标准输出,可通过 `docker logs` 查看 83 | * 暴露 80 端口 84 | 85 | 接着,下载项目所需的依赖工具 `bower`,`gulp` 86 | 87 | ``` 88 | RUN npm install -g bower gulp 89 | 90 | WORKDIR /app 91 | ``` 92 | 93 | 紧接着,优先将 `./package.json` 和 `./bower.json` 复制到镜像中,预先加载第三方依赖。 94 | 95 | ``` 96 | COPY ./package.json /app/ 97 | COPY ./bower.json /app/ 98 | 99 | RUN npm install && bower install --allow-root 100 | ``` 101 | 102 | * bower 默认不允许 Root 权限运行,所以要加入 --allow-root 参数。 103 | 104 | 105 | 然后,执行 Angular 构建命令,将构建生成的静态文件复制到 Web 根目录 106 | 107 | ``` 108 | COPY . /app/ 109 | 110 | RUN gulp build 111 | 112 | RUN cp -R /app/dist/* /usr/share/nginx/html 113 | ``` 114 | 115 | 最后,设置 Docker 默认运行命令,启动 Nginx 为前台运行。 116 | 117 | ``` 118 | CMD ["nginx", "-g", "daemon off;"] 119 | ``` 120 | 121 | * Nginx 设置为前台运行主要是为了 Docker 容器启动不中断。 122 | 123 | ### 构建 Docker Image 124 | 125 | 完整的 Dockerfile 126 | 127 | ``` 128 | FROM node:0.12.7-wheezy 129 | 130 | MAINTAINER YeTing "me@yeting.info" 131 | 132 | RUN apt-key adv --keyserver pgp.mit.edu --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 133 | RUN echo "deb http://nginx.org/packages/mainline/debian/ wheezy nginx" >> /etc/apt/sources.list 134 | 135 | ENV NGINX_VERSION 1.7.12-1~wheezy 136 | 137 | RUN apt-get update && \ 138 | apt-get install -y ca-certificates nginx && \ 139 | rm -rf /var/lib/apt/lists/* 140 | 141 | # forward request and error logs to docker log collector 142 | RUN ln -sf /dev/stdout /var/log/nginx/access.log 143 | RUN ln -sf /dev/stderr /var/log/nginx/error.log 144 | 145 | EXPOSE 80 146 | 147 | RUN npm install -g bower gulp 148 | 149 | WORKDIR /app 150 | 151 | COPY ./package.json /app/ 152 | COPY ./bower.json /app/ 153 | RUN npm install && bower install --allow-root 154 | 155 | COPY . /app/ 156 | 157 | RUN gulp build 158 | 159 | RUN cp -R /app/dist/* /usr/share/nginx/html 160 | 161 | CMD ["nginx", "-g", "daemon off;"] 162 | ``` 163 | 164 | 有了 Dockerfile 以后,我们可以运行下面的命令构建前端镜像并命名为 my-angular-app: 165 | 166 | ```bash 167 | docker build -t my-angular-app . 168 | ``` 169 | 170 | ### 部署 Docker Image 171 | 172 | 最后,让我们从镜像启动容器: 173 | 174 | ``` 175 | docker run -p 80:80 my-angular-app 176 | ``` 177 | 178 | 这样子我们就能从 80 端口去访问我们的 Angular 应用 179 | 180 | 181 | 非常好,我们现在已经得到了一个优良的 Angular Docker Seed ,快来加入你的逻辑去完成你的 Angular 应用吧。 -------------------------------------------------------------------------------- /front-end-deploy.md: -------------------------------------------------------------------------------- 1 | ## 也许让运维也学学前端,那么天下就太平了 2 | >目标:定义 Docker 与前端的关系,介绍前端部署的几种方式,阐述 Docker 化的前端的优点所在 3 | 4 | 今天我们来讲讲前端与 Docker 之间的关系 5 | 6 | Docker 是运维工具而不是开发工具。 7 | 8 | 很多前端工程师把 Docker 想象成开发工具,来回推敲自己的开发过程,却找不到任何一个地方需要用到 Docker,所以对于 Docker 他们常常认为这个一个负担。 9 | 10 | 说实话,Docker 跟前端开发并没有什么关系。 11 | 反而 Docker 的引入对前端开发有了更多的要求,让前端开发者需要做开发流程之外的事情。 12 | 那么为什么我们还是要使用 Docker ? 13 | 14 | 说说我,为什么要使用 Docker。 15 | 16 | 前端部署的各个阶段 17 | 18 | ### 前端部署之 FTP 19 | 20 | 以前,我们的项目是用 Angular + grunt 的前端应用。 21 | 我们将环境分为 develop, test ,production 三个环境,对应不同的 API Url及配置。 22 | 为了方面我们的部署,针对不同的环境我们做了不同的构建任务 23 | 例如:grunt build:develop 、grunt build:test 和 grunt build:production 。 24 | 每次前端构建之后,将会生成一系列经过静态文件,将这些静态文件放到 Web 服务器服目录就可以被访问了。 25 | 26 | 每次需要上线前端项目,我都需要直连到服务器,把构建好的静态文件丢上去。 27 | 简单粗暴,但是久而久之问题就来了: 28 | 29 | 1. 直连服务器,安全肯定得不到保证。 30 | 2. 不论哪个环境项目上线都需要我参与。也许让运维也学学前端,那么天下就太平了 31 | 3. 上线项目的方式不够灵活,由较大的局限。 32 | 33 | ### 前端部署之 Jenkins 34 | 35 | 后来,我司运维引进 Jenkins 据说能实现自动化部署,听着这个自动化就感觉高端大气上档次。不过我司运维话锋一转说配置较为复杂。我想复杂就复杂吧,通过 Jenkins 能实现自动化,解决之前的几个问题,能把我从无尽的运维中拯救出来,让我安安静静地做一个前端就好了。 36 | 37 | 我司运维经过了 git访问权限配置,定时检测更新配置,更新脚本编写(也就10来行,不过我司运维与我共同写的),发现 Jenkins 就配置的差不多的,但是一运行就报错。他找不到问题,让我来看看。 38 | 无奈发现当前主机没有前端构建需要的 node 和 grunt 。也许让运维也学学前端,那么天下就太平了。怎么办,装呗。终于历经千万,我们的自动化流程跑起来了,每次我一上传代码,Jenkins 就能帮我把代码发布到环境上。感觉真好。简直是配置过一次就不想再配置第二次。但是奈何,我们当前的前端项目有4个,继续配置之。 39 | 40 | 配置好之后的 Jenkins 简直是可爱,帮我从无尽的运维之中解出来,我可以安静的做一个前端了 41 | 42 | 但是好日子没过多久,随着项目的复杂度增加,相同项目在不同的分支上对第三方依赖的版本也略略有些许区别,导致环境上前端展示的效果和开发展示的效果不同,一狠心,针对 develop 和 release (git分支采用gitflow)分支单独进行配置。但是前端项目有4个,还是都配置吧。这样子 4 * 2 = 8 (master生产环境分支是单独配置的) 简直了,自己挖的坑,哭着也要填完。 43 | 44 | (番外:一个月后,服务器坏了,所有的配置的都需要重来一遍,也许让运维也学学前端,那么天下就太平了。) 45 | 46 | 说说好处: 47 | 48 | 1. 通过 Jenkins 作为中转避免了直连服务器, 49 | 2. Jenkins 实现了代码的自动化部署,只需提交代码便可上线环境 50 | 3. Jenkins 提供手动执行任务的功能和权限管理的能力。上线方式相当的灵活。 51 | 52 | 说说问题: 53 | 54 | 1. Jenkins 配置繁琐,特别是多个项目多个分支都得配置的时候简直不能更丧心病狂。 55 | 2. Jenkins 执行的命令都是依赖于本机环境,如果出现 项目 A 依赖的 Node 版本是 0.10.10 ,项目 B 依赖的 Node 版本是 0.12.2 ,这个的配置就更加复杂了(我们后来对 项目 A 的 Node 版本进行了升级) 56 | 57 | ### 前端部署之 Docker 58 | 59 | 机缘巧合,我遇到了 [Docker](https://www.docker.com/) ,其实 Docker 和 Jenkins 可以搭配着使用,上述 Jenkins 的一些问题,但是 Jenkins 给我的印象是在是太深刻,我直接放弃了,再加上市面上也有很多基于 Docker 的 CI/CD 工具使用起来都特别的方便,例如: [Daocloud](https://www.daocloud.io/) 和 [Gitlab CI](https://ci.gitlab.com/)(相关链接中有两篇讲解如何搭建持续集成环境文章)。 60 | 61 | Docker 是容器管理引擎,他的核心理念就是构建一次,可以运行在任何一地方可以运行容器的地方。 62 | 63 | 当然引入 Docker 到我们的项目开发部署流程之中,我们在开发中的里面也会做一些调整。根据项目来编写该项目的 Dockerfile ,在本地如果能正常运行,再也不用担心在服务器上会有各种各样由环境不同引发的奇葩问题。由于 Docker Image 是标准的交付件,所以基于 Docker 自动化部署和自动化发布会变得非常方便,结合市面上 Docker CI/CD 厂商,我们能非常方便的实现`开发>测试>部署`自动化。 64 | 65 | 引入 Docker 也许对前端开发没有帮助,甚至对前端开发来说是需要多掌握一门技能的负担,但是放眼前端开发及部署的整体流程,他将前端项目环境搭建的工作交给了前端,而不是运维,让最熟悉的人做最熟悉的事情,效率成倍提高。 66 | 这也是我推崇用 Docker 部署前端的原因。 67 | 68 | 最后再用本文的核心来作为文章的总结:也许让运维也学学前端,那么天下就太平了。我们前端就不用这么折腾了。 69 | 70 | 相关链接 71 | 72 | * [基于Docker 与 DaoCloud 建立简单够用的持续集成环境](https://github.com/Ye-Ting/docker-ci/blob/master/daocloud.md) 73 | * [基于docker 与 gitlab CI 做一个简单够用的持续集成环境](https://github.com/Ye-Ting/docker-ci/blob/master/gitlab.md) 74 | * [Web研发模式的演变](https://github.com/lifesinger/lifesinger.github.com/issues/184) -------------------------------------------------------------------------------- /front-end-express.md: -------------------------------------------------------------------------------- 1 | ## Node Express Docker 2 | > 目标: 用 Docker 镜像的方式搭建 Node Express 应用 3 | 4 | 本项目代码 [node-express-docker-sample](https://github.com/Ye-Ting/node-express-docker-sample) 5 | 6 | Demo :http://yeting-front-node-express-docker-sample.daoapp.io/ 7 | 8 | ### Node Express 应用搭建 9 | 10 | 首先,借助 [Yeomen Express generator ](https://github.com/petecoop/generator-express) 生成一个 Node Express 应用 11 | 12 | 具体的操作都在上面的 Repo 中有说明,这里不做赘述。 13 | 14 | 值得注意的是: 15 | 16 | * Express 默认暴露 3000 端口,通过环境变量 PORT 修改 17 | * 启动命令 node bin/www 18 | * 调试命令 gulp 19 | 20 | ### Dockerfile 编写 21 | 22 | 首先,选择官方的 node 镜像作为项目的基础镜像。 23 | 24 | ``` 25 | FROM node:0.12.7-wheezy 26 | 27 | MAINTAINER YeTing "me@yeting.info" 28 | ``` 29 | 30 | 接着,优先将 `./package.json` 复制到镜像中,预先加载第三方依赖。 31 | 32 | ``` 33 | WORKDIR /app 34 | 35 | COPY ./package.json /app/ 36 | 37 | RUN npm install 38 | ``` 39 | 40 | * 每次 Dokcer 构建成功之后就会有缓存,这样的写法能提高缓存的命中率,优化 Docker 构建镜像的速度 41 | 42 | 最后,将 Express 应用程序复制到 /app,暴露 3000 端口 43 | 44 | ``` 45 | COPY . /app/ 46 | 47 | EXPOSE 3000 48 | 49 | CMD node bin/www 50 | ``` 51 | 52 | * Docker Container 之间是通过 link 机制来做通信的,EXPOSE 3000 ,是别的容器想要访问 该容器 3000 端口的前提条件。 53 | 54 | ### 构建 Docker Image 55 | 56 | 完整的 Dockerfile 57 | 58 | ``` 59 | FROM node:0.12.7-wheezy 60 | 61 | MAINTAINER YeTing "me@yeting.info" 62 | 63 | WORKDIR /app 64 | 65 | COPY ./package.json /app/ 66 | 67 | RUN npm install 68 | 69 | COPY . /app/ 70 | 71 | EXPOSE 3000 72 | 73 | CMD node bin/www 74 | ``` 75 | 76 | 有了 Dockerfile 以后,我们可以运行下面的命令构建前端镜像并命名为 my-express-app: 77 | 78 | ```bash 79 | docker build -t my-express-app . 80 | ``` 81 | 82 | ### 部署 Docker Image 83 | 84 | 最后,让我们从镜像启动容器: 85 | 86 | ``` 87 | docker run -p 80:3000 my-express-app 88 | ``` 89 | 90 | 这样子我们就能从 80 端口去访问我们的 Express 应用 91 | 92 | 93 | ### Node Express 应用运行优化 94 | 95 | 当然, Node 是公认的不稳定,经常会出现服务器内存溢出,而奔溃退出。 96 | 97 | 我们针对这一点,可以对 Express 启动命令做优化。 98 | 引入 forever 插件,通过 forever 来启动 express 应用。 99 | 100 | Dockerfile 101 | 102 | ``` 103 | FROM node:0.12.7-wheezy 104 | 105 | MAINTAINER YeTing "me@yeting.info" 106 | 107 | WORKDIR /app 108 | 109 | RUN npm install -g forever 110 | 111 | COPY ./package.json /app/ 112 | 113 | RUN npm install 114 | 115 | COPY . /app/ 116 | 117 | EXPOSE 3000 118 | 119 | CMD forever bin/www 120 | ``` 121 | 122 | 非常好,我们现在已经得到了一个优良的 Express Docker Seed ,快来加入你的逻辑去完成你的 Express 应用吧。 -------------------------------------------------------------------------------- /front-end-hello.md: -------------------------------------------------------------------------------- 1 | ## Hello Docker 2 | > 目标:使用静态页面来完成一个简单的 Docker Demo 3 | 4 | 本项目代码维护在 [front-end-docker-sample](https://github.com/Ye-Ting/front-end-docker-sample) 5 | 6 | Demo 地址 :http://yeting-front-end-docker-sample.daoapp.io/ 7 | 8 | ### Docker 化应用的关键元素 9 | 10 | * 镜像是 Docker 应用的静态表示,是应用的交付件,镜像中包含了应用运行所需的所有依赖:包括应用代码、应用依赖库、应用运行时和操作系统。 11 | * Dockerfile 是一个描述文件,描述了产生 Docker 镜像的过程。详细文档请参见 Dockerfile文档 12 | * 容器是镜像运行时的动态表示,如果把镜像想象为一个 Class 那么容器就是这个 Class 的 instance 实例。 13 | 一个应用 Docker 化的第一步就是通过 Dockerfile 产生应用镜像。 14 | 15 | ### 编写 Dockerfile 16 | 17 | 本次基础镜像使用 Nginx 官方镜像,也可以根据自己的项目需求与环境依赖使用定制基础镜像。 18 | 19 | Dockerfile 20 | 21 | 首先,选择官方的 nginx 镜像作为项目的基础镜像。 22 | 23 | ``` 24 | FROM nginx 25 | 26 | MAINTAINER YeTing "me@yeting.info" 27 | ``` 28 | 29 | 接着,将代码复制到目标目录。 30 | 31 | ``` 32 | COPY . /usr/share/nginx/html 33 | ``` 34 | 35 | * ADD 与 COPY 的区别,总体来说 ADD 和 COPY 都是添加文件的操作,其中 ADD 比 COPY 功能更多,ADD 允许后面的参数为 URL,还有 ADD 添加的文件为压缩包的话,它将自动解压。 36 | * CMD 为本次构建出来的镜像运行起来时候默认执行的命令,我们可以通过 docker run 的启动命令修改默认运行命令。 37 | * Dockerfile 具体语法请参考:[Dockerfile](https://docs.docker.com/reference/builder/)。 38 | 39 | ### 构建 Docker Image 40 | 41 | 有了 Dockerfile 以后,我们可以运行下面的命令构建前端镜像并命名为 my-front-end-app: 42 | 43 | ```bash 44 | docker build -t my-front-end-app . 45 | ``` 46 | 47 | ### 部署 Docker Image 48 | 49 | 最后,让我们从镜像启动容器: 50 | 51 | ``` 52 | docker run -p 80:80 my-front-end-app 53 | ``` 54 | 55 | 如果看到这界面,那么就说明你成功进入到了一个 Docker 化的世界。 56 | 57 | ``` 58 | Hello Docker !! 59 | 60 | 欢迎进入 Docker 的世界!! 61 | ``` 62 | 63 | --------------------------------------------------------------------------------