Angular 容器部署的方法


Posted in Javascript onApril 17, 2018

很多人反应很难访问 Github Page,所以 ng-alain.com 转移到阿里云服务器上,因此做了一次完整的 Angular 容器部署。

以下我会阐述 ng-alain 整个过程,其中包括 Docker、Nginx、Let's Sencrypt 证书等范涛,我无法保证新手可以很好的阅读她,不过你可以通过一些文章关键字在搜索引擎获得更多资料。

我们知道Docker有两个很重要的概念:镜像、容器。而Anguar容器部署只需要把Angular构建的生产环境(例如:ng build -prod)产生的目录 dist 写入至一个静态服务器镜像(例如:Nginx),最后实例这个镜像。

一、构建Angular镜像

1、编译Angular

一般而言会把 Angular 构建也在一个容器内完成,在 Angular 项目根目录下创建 Dockerfile.compile 文件:

FROM node:8

LABEL authors="cipchk <cipchk@qq.com>"

WORKDIR /usr/src/app

COPY package.json package.json

RUN npm config set registry https://registry.npm.taobao.org \
  && npm i

COPY . .

RUN ng build --prod
  1. FROM 指定一个 node 基础镜像,这是构建 Angular 项目的最简的基本
  2. LABEL 镜像元数据,例如 authors 作者信息
  3. WORKDIR 指定镜像内工作目录
  4. COPY 复制项目 package.json 并安装依赖包
  5. RUN 复制项目文件后并执行 ng build 命令

最后,执行构建镜像命令:

docker build -f Dockerfile.build -t ng-app-build .

其中 ng-app-build 表示镜像名称。

2、Angular 运行环境

我们并不会基于编译 Angular 镜像基础上构建 Angualr 运行环境镜像,因此里头包括很多无意义的文件,例如 npm i 产生的 node_modules。而是从上述镜像提取 dist 目录,并产生一个新镜像;Angular 运行环境应该是一个干净、简单的。

因此,从编译 Angular 镜像提取 dist:

# 运行编译 Angular 镜像
docker run --name ng-app-build ng-app-build
# 将 `dist` 复制到项目根目录下
docker cp ng-app-build:/usr/src/app/dist ./dist/
# 删除编译 Angular 镜像实例
docker rm -f ng-app-build

注意: 容器路径必须上一步 Angular 编译的 WORKDIR 路径

最后,在 Angular 项目根目录下创建 Dockerfile.package 文件:

FROM nginx

COPY _nginx/default.conf /etc/nginx/conf.d/

RUN rm -rf /usr/share/nginx/html/*

COPY /dist /usr/share/nginx/html

CMD ["nginx", "-g", "daemon off;"]

参数和上一节略同,只是将提取的 dist 写入到镜像内的 Nginx 默认运行目录里。

同时把 Angular 项目的 _nginx/default.conf 作为 Nginx 的配置文件,在项目里包括 Nginx 配置,像使用HTML5路由策略时需要处理 404 问题、GZip等。

但是我比较建设这里的 Nginx 配置应该极简单化,把一些 GZip、SSL 统一在反向代理层上完成,毕竟容器化后的应用不可能在一台机器上只部署一个应用。

以下是一个 Angular 应用最简化的配置信息:

server {
  listen    80;

  server_name localhost;

  location / {
    root  /usr/share/nginx/html;
    index index.html index.htm;
    try_files $uri $uri/ /index.html;
  }

  error_page  500 502 503 504 /50x.html;
  location = /50x.html {
    root  /usr/share/nginx/html;
  }
}

try_files 可以保证当访问的路径未找到文件时直接使用 index.html 文件替代,这也就是 Angular HTML5 路由策略很重要的一环。

最后,构建生产环境镜像:

docker build -f Dockerfile -t ng-app .

当然,这个时候的编译 Angular 镜像已经没有存在的意义了。

docker rmi -f ng-app-build

二、运行Angular

我们可以查看已经存在的镜像:

docker images

当然,上述在 Nginx 配置采用的是一个 80 端口,因此可以直接使用:

docker run -d -p 80:80 \
  --name web \
  ng-app

若你域名绑定了该主机,则可以直接访问。至此,已经是 Angular 容器化后所有内容,下面是关于 Nginx 反向代理 Docker 应用的部分,若你已经这么做,那直接忽略下一章节。

Nginx 反向代理

绝大多数情况下会利用一个代理服务器容器,来转发多个站点,因此很少会直接在一个 Angular 站点里直接使用 80 端口,而是透过另一个代理层进行转发。

在之前我尝试使用jwilder/nginx-proxy 镜像来处理,它真的非常方便,但是在SSL环节让我吃了很多苦头,最后放弃之,而改用直接在主机上安装 Nginx 作为反向代理。
在Angular容器化过程中,我们并未配置任何 SSL、GZip 等,只是保留 Nginx 服务所需的配置项而已,而这一部分我们可以放在反向代理层完成。

这个过程包括三个步骤:安装 Nginx、安装 acme.sh 签发 Let's Sencrypt 证书、配置并运行 Nginx。

1、安装Nginx

以 CenOS7 为例,更多系统请自行Google:

sudo yum install epel-release
sudo yum install nginx
# 启动Nginx
sudo systemctl start nginx

2、通过acme.sh签发证书

acme.sh 是国内一大牛写的用于简化申请 Let's Sencrypt 证书,并自动续签证书,几乎上第一次安装完全后,后续都无须人工干预。

Let's Sencrypt 不久前发布支持泛域,因此这一次也是申请了 *.ng-alain.com 泛域证书。

安装 acem.sh:

curl https://get.acme.sh | sh

这里我使用DNS来签发证书,目前支持几十种服务商,当然包括阿里云:

export Ali_Key="aaaaaaaaaaa"
export Ali_Secret="xxxxxxxxxxxxxxxx"
acme.sh --issue --dns dns_ali -d ng-alain.com -d *.ng-alain.com

Ali_Key 和 Ali_Secret 是对应的阿里云的 Access key,注意要给予 DNS 授权。

最后,利用 --installcert 来提取 Nginx 所需要的证书文件。

acme.sh --installcert \
  -d ng-alain.com \
  --key-file $(pwd)/proxy/certs/ng-alain.com.key \
  --fullchain-file $(pwd)/proxy/certs/fullchain.cer \
  --reloadcmd "service nginx force-reload"

acme.sh 会纪录这行命令的所有细节,并且当自动续签触发后再一次执行它们。其中 service nginx force-reload 是指命令执行完成后重启 nginx 使启证书立刻生效。

整个过程我非常顺利,没有任何错误,acme.sh 也有很多说明文档,包括中文,有关更多细节请自行阅读。

3、运行 Nginx

之前在安装 Nginx 时我们就已经启动了,那么,我们只需要对 /etc/nginx/nginx.conf 编写一些 Nginx 配置即可。

有两个主要细节:SSL配置和代理转化Angular容器实例端口的配置。

对于前者,若你在运行上述命令时依然保持路径的话,则:

ssl_certificate /root/proxy/certs/fullchain.cer;
ssl_certificate_key /root/proxy/certs/ng-alain.com.key;
ssl_session_timeout 30m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
ssl_session_cache shared:SSL:10m;
ssl_prefer_server_ciphers on;

而对于代理转化,这其决于你映射Angular容器的端口,例如上述在运行容器的命令是这样:

docker run -d -p 80:80 \
  --name web \
  ng-app

我们可以重新换另一个映射端口,例如:8001。

docker kill web
docker run -d -p 8001:80 \
  --name web \
  ng-app

然后在 Nginx 配置相应的代理转化:

server {
  listen 80;
  server_name ng-alain.com www.ng-alain.com;
  return 301 https://$server_name$request_uri;
}

server {
  listen 443 ssl http2;
  server_name ng-alain.com www.ng-alain.com;

  location / {
    proxy_pass http://127.0.0.1:8001/;
  }
}
  1. server 这里有两个分别对 80 和 443,前者强制跳转 https,当你不希望用户使用 http 访问你站点时。
  2. server_name 指定监听的域名
  3. proxy_pass 指定代理转发域,8001 端口就是上述 Angular 应用所处容器所映射的端口

配置文件保持后,你可以先执行 nginx -t 来校验配置文件是否正确。

最后,重启 Nginx。

service nginx force-reload

三、持续部署

上述有系列的 Docker 命令甚是繁琐,应该把这一切自动化,有个专业名称叫:持续部署(简称:cd);ng-alain.com 现在是使用DaoCloud 完成这项工作。

DaoCloud 提供一种叫【安全镜像】的构建功能,分为三个步骤——编译、提取、打包;等同上述 Angular 项目的编译、提供和发布。

只需要在项目下创建 daocloud.yml;它是 DaoCloud 提供的一种自定义项目流程的定义文件,若你对上述已经了解,再来看它就不会非常陌生。以下是 ng-alain.com 完整的 daocloud.yml 内容:

version: 3
stages:
- compile
- deploy
release:
 stage: compile
 job_type: lite_image_build
 only:
  branches:
  - master
 allow_failure: false
 compile:
  build_dir: /
  cache: false
  dockerfile_path: /Dockerfile.compile
 extract:
 - /usr/src/app/dist
 - /usr/src/app/_nginx/default.conf
 package:
  build_dir: /
  cache: false
  dockerfile_path: /Dockerfile.package
self:
 stage: deploy
 job_type: DCS_deploy
 only:
  branches:
  - master
 allow_failure: false
 dependencies:
 - release
 app_name: web
 cluster_id: ""

注意: 其中 extract 务必包含完整路径。

四、总结

将生产环境容器化已经是一种架构标准,上述只是在部署ng-alain.com 的一些总结,实际可能遇到的问题会更多,大家可以通过以下找到答案:

Docker — 从入门到实践
Docker 问答录(100 问)
DaoCloud Services 文档

当然,未来Angular cli 也将会内置 Docker 部署,这里有一份来自 Angular 的相关ng docker 命令的设计文档。

以上所有代码可以在 delon 上找得到,可能存在个人路径不同罢了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js中document.write使用过程中的一点疑问解答
Mar 20 Javascript
json中换行符的处理方法示例介绍
Jun 10 Javascript
jquery复选框多选赋值给文本框的方法
Jan 27 Javascript
Bootstrap基础学习
Jun 16 Javascript
JavaScript包装对象使用详解
Jul 09 Javascript
微信小程序教程系列之视图层的条件渲染(10)
Apr 19 Javascript
vue中子组件的methods中获取到props中的值方法
Aug 27 Javascript
详解微信小程序-canvas绘制文字实现自动换行
Apr 26 Javascript
详解小程序开发经验:多页面数据同步
May 18 Javascript
RxJS的入门指引和初步应用
Jun 15 Javascript
微信小程序实现页面跳转传递参数(实体,对象)
Aug 12 Javascript
小程序实现日历左右滑动效果
Oct 21 Javascript
bootstrap中日历范围选择插件daterangepicker的使用详解
Apr 17 #Javascript
jQuery简单判断值是否存在于数组中的方法示例
Apr 17 #jQuery
Vue 项目代理设置的优化
Apr 17 #Javascript
在 Typescript 中使用可被复用的 Vue Mixin功能
Apr 17 #Javascript
vue iview实现动态路由和权限验证功能
Apr 17 #Javascript
基于VuePress 轻量级静态网站生成器的实现方法
Apr 17 #Javascript
Vue-cropper 图片裁剪的基本原理及思路讲解
Apr 17 #Javascript
You might like
PHP中读写文件实现代码
2011/10/20 PHP
PHP页面跳转实现延时跳转的方法
2016/12/10 PHP
微信公众平台开发-微信服务器IP接口实例(含源码)
2017/03/05 PHP
使用PHP+Redis实现延迟任务,实现自动取消订单功能
2019/11/21 PHP
重写javascript中window.confirm的行为
2012/10/21 Javascript
浅析2种JavaScript继承方式
2015/12/04 Javascript
AngularJS 日期格式化详解
2015/12/23 Javascript
js实现页面跳转的五种方法推荐
2016/03/10 Javascript
浅析创建javascript对象的方法
2016/05/13 Javascript
jQuery实现打开网页自动弹出遮罩层或点击弹出遮罩层功能示例
2017/10/19 jQuery
浅谈Vue内置component组件的应用场景
2018/03/27 Javascript
js Element Traversal规范中的元素遍历方法
2018/04/19 Javascript
Vue 使用中的小技巧
2018/04/26 Javascript
js实现随机8位验证码
2020/07/24 Javascript
用于统计项目中代码总行数的Python脚本分享
2015/04/21 Python
Python中使用items()方法返回字典元素对的教程
2015/05/21 Python
python爬虫headers设置后无效的解决方法
2017/10/21 Python
Python语言实现将图片转化为html页面
2017/12/06 Python
python实现批量图片格式转换
2020/06/16 Python
TensorFlow 滑动平均的示例代码
2018/06/19 Python
python logging添加filter教程
2019/12/24 Python
基于Django OneToOneField和ForeignKey的区别详解
2020/03/30 Python
解决Keras自带数据集与预训练model下载太慢问题
2020/06/12 Python
Python下使用Trackbar实现绘图板
2020/10/27 Python
深入理解css属性的选择对动画性能的影响
2016/04/20 HTML / CSS
印尼美容产品购物网站:PerfectBeauty.id
2017/12/01 全球购物
什么是SCM(软件配置管理)
2014/08/16 面试题
金融行业务员的自我评价
2013/12/13 职场文书
清扬洗发水广告词
2014/03/14 职场文书
房屋租赁协议书范本
2014/04/10 职场文书
制冷与空调专业毕业生推荐信
2014/07/07 职场文书
社区服务活动小结
2014/07/08 职场文书
助人为乐道德模范事迹材料
2014/08/16 职场文书
2015年妇委会工作总结
2015/05/22 职场文书
团结友爱主题班会
2015/08/13 职场文书
爱国主题班会教案
2015/08/14 职场文书