1 前言

上一周的工作中,有这样一个需求,在不同的环境下(dev, test, beta, release)传入不同的值,首先是以业务为首要目标,因此,博主最初的做法是通过判断不同的hostname来传入不同的值,这种做法简单快捷,但是存在以下两个缺点:
1)hostname更改时需要修改代码,当多个服务均存在这种需求时,工作量就出来了
2)服务不解耦,需要手动调整
3)略显low,并且代码看着感觉很不舒服
因此,博主今天决定做优化改善,通过获取 docker 的环境变量来获取当前的运行环境,一劳永逸,博主以下的最小示例采用的Vue,也同样适用于React Angular JQ

因为其中原理需要在项目实现完成才更好说明,因此,博主首先将实现的过程讲解出来,也许会有很多不明白的地方,所以,实现完成后,博主会逐一解释。

2 最小完整实现
2.1 创建最小vue项目

既然要最小最快捷,因此直接使用vue脚手架拉去一个项目即可

mkdir Get_Docker_ENV  
# 创建Get_Docker_ENV文件夹
cd Get_Docker_ENV
# 进入Get_Docker_ENV文件夹
vue create vue_app
# 利用vue脚手架创建vue_app项目

等待脚手架自动拉取项目,拉取完成即可,
在这里插入图片描述
拉取完成的项目目录如下,在 main.js 中添加如下代码,具体为什么要添加这些代码,项目实践完成博主会详解的。

const ENV_NOW = document.querySelector("html").getAttribute("env_now");
// 获取html标签的env_now属性值
if (ENV_NOW) {
  Vue.prototype.$ENV_NOW = `${ENV_NOW}`;
  // 将$ENV_NOW设置为vue全局变量
}

在app.vue中的export default添加如下代码

  created() {
    console.log(this.$ENV_NOW);
  }
  // 打印出 this.$ENV_NOW ,主要是为测试能否获取到这个变量

修改完成后打包构建项目

yarn run build
# 构建项目

此时会生成一个 dist 文件,也就是项目构建完成后的文件

2.2 利用dockerfile构建镜像和运行容器

在当前目录下进行

vim dockerfile
# 创建并打开dockerfile

此时编辑dockerfile文件

FROM nginx
# 以nginx为基础镜像
COPY ./vue_app/dist/ /usr/share/nginx/html/
# 复制 ./vue_app/dist/ 到 /usr/share/nginx/html/
# /usr/share/nginx/html/为 nginx 默认的启动文件夹
CMD ["/bin/bash", "-c", "sed -i \"s@<html@<html env_now=\"$ENV\"@\" /usr/share/nginx/html/index.html; nginx -g \"daemon off;\""]
# 启动命令
# "sed -i \"s@<html@<html env_now=\"$ENV\"@\" /usr/share/nginx/html/index.html;"
# 这行代码是指将/usr/share/nginx/html/index.html中的<html 替换成 <html env_now=\"$ENV\" 
# 也就是说,当docker run 时,index.html中的html标签就添加了这样一个属性

运行时,只要在docker run时将ENV这个变量传进便可

2.3 创建镜像和运行容器

Docker build -t nginx_vue .

docker build -t nginx_vue .
# 根据dockerfile来创建nginx_vue镜像
docker run -p 6090:80 -e ENV=’now_env’ -d -t nginx_vue
# 以nginx_vue为镜像运行容器并传入环境变量ENV=’now_env’
2.4 运行测试

此时便可以在本地访问 localhost:6090 就可以看到运行的项目 ,并且可以在控制台看到打印出 now_env 了,也就是项目拿到这个变量了;
同时,检查 Elements 会看到,此时的 html 中动态地添加了这样一个属性。
在这里插入图片描述

3 详解

其实相信看到这里,大部分同学已经理解实践的过程了,博主在这里梳理一下,
(1)最终的实现是在构建好的 index.html 的 html 标签中添加了一个属性,通过动态地给这个属性传值,实现获取docker的环境变量
(2)在 html 中提前获取这个值并复制到vue全局中,这样 vue 项目中便可以拿到了

因此,这种实现方式不局限于框架,Vue React Angular 均可以使用。

4 总结

博主实现后实际测试过,完全没有问题,但是,但是博主晚上一直在思考,这样做虽然比判断 hotsname 好很多,完全解决了hostname带来的缺陷,但是,修改 html, 获取 html 的属性值,始终有种不是很正式的样子,如果能够动态的直接传一个变量到项目中,那就好了,但是这种方式博主始终未能实现,主要原因如下:
(1) docker 镜像是项目已经构建好了,也就是说此时的项目已经是构建好了的,动态传值难

写着写着,博主似乎有了思路,就是把项目不构建,在构建镜像时再启动项目构建然后传值。先这样试试,有了新进展再记录

Logo

前往低代码交流专区

更多推荐