内容简介:前段时间,自己搞了个阿里云的服务器。想自己在上面折腾,但是不想因为自己瞎折腾而污染了现有的环境。毕竟,现在的阿里云已经没有免费的快照服务了。要想还原的话,最简单的办法就是重新装系统。而一旦重装,之前的搭建的所有环境就都白搭了。再加上之前本身就想引入docker,所以就打算利用docker容器来部署这次的前端应用。在打包之前,首先需要一个可正常运行的前端应用。这个可以使用
1.前言
前段时间,自己搞了个阿里云的服务器。想自己在上面折腾,但是不想因为自己瞎折腾而污染了现有的环境。毕竟,现在的阿里云已经没有免费的快照服务了。要想还原的话,最简单的办法就是重新装系统。而一旦重装,之前的搭建的所有环境就都白搭了。
再加上之前本身就想引入docker,所以就打算利用 docker 容器来部署这次的前端应用。
2.构建前端应用
在打包之前,首先需要一个可正常运行的前端应用。这个可以使用 umi 或者 create-react-app 来构建。
3.nginx的默认配置文件
然后需要在项目中加上默认nginx配置文件。
server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; } }
4.编写本地构建脚本
4.1. 移除上次的目录和Dockerfile
#!/bin/bash if [ -d "./dist" ]; then rm -rf ./dist fi if [ -f "./Dockerfile" ]; then rm -f ./Dockerfile fi
因为每次更改后dist中的内容肯定与之前不同,其实这一步显得不是那么必要。运行npm的打包命令也会自动清楚该目录。
而清除Dockerfile则是为了防止更新了Dockerfile,而这次却不能得到最新的配置。
4.2. 打包前端应用
执行前端的打包命令,生成静态文件目录。
yarn build
4.3. 生成Dockerfile
echo "FROM nginx:latest" >> ./Dockerfile echo "COPY ./dist /usr/share/nginx/html/" >> ./Dockerfile echo "COPY ./default.conf /etc/nginx/conf.d/" >> ./Dockerfile echo "EXPOSE 80" >> ./Dockerfile
FROM
制定了该定制容器的基础镜像为 nginx:latest
; COPY
命里将打包好的静态文件目录复制到容器内的 /usr/share/nginx/html/
目录下,然后将nginx的配置写入容器中对应的位置; EXPOSE
则是设置对外暴露容器的80端口。
4.4. 生成并推送定制image
docker build -t detectivehlh/mine . docker login -u detectivehlh -p ******** docker push detectivehlh/mine
这里是在开发本地,使用docker命令来打包,所以该脚本对docker有强依赖。 build
命令表示打包docker应用的, -t
选项则制定了docker镜像的名字和tag,tag会默认为latest。
然后登录dockerHub,将定制好的镜像推送到dockerHub中。 detectivehlh
就是dockerHub的用户名, mine
是image的名字。
4.5. 删除tag为none的无用image
第一次构建不会生成tag为 none
的image,但是后面每次再次执行该命令就会出现这样的情况。所以每次构建了一个新的image后,需要清除调不需要的image。
docker images | grep none | awk '{print $3}' | xargs docker rmi
使用 grep
命令匹配到tag为 none
的image, awk
是一个强大的文本分析工具, {print $3}
表示打印出匹配到的每一行的第三个字段,也就是docker的 image id
。如果是 $0
的话表示当前整行的数据。
xargs
是一个给其他命令(也就是后面的docker rmi)传递参数的一个过滤器,将标准输入转换成命令行参数。
总结来说,上述命令就是找到tag为 none
的image的ID,然后使用docker rmi命令移除该image。
4.6. 执行部署
cmd="cd ~ && sh deploy.sh mine" ssh -t USER_NAME@IP_ADDRESS "bash -c \"${cmd}\""
通过ssh命令,登录远程服务器,并且执行参数中的脚本。
deploy.sh
是放在服务端的构建脚本。放在默认的登录用户下。我们发现,后面还跟了个mine,这是在服务器上运行的docker镜像的名字。这里暂时没有对container的名字加上hash,因为自己的小项目,暂时没有必要。
在项目中的完整构建脚本如下。
#!/bin/bash if [ -d "./dist" ]; then rm -rf ./dist fi if [ -f "./Dockerfile" ]; then rm -f ./Dockerfile fi yarn build echo "FROM nginx:latest" >> ./Dockerfile echo "COPY ./dist /usr/share/nginx/html/" >> ./Dockerfile echo "COPY ./default.conf /etc/nginx/conf.d/" >> ./Dockerfile echo "EXPOSE 80" >> ./Dockerfile docker build -t detectivehlh/mine . docker login -u detectivehlh -p ******** docker push detectivehlh/mine docker images | grep none | awk '{print $3}' | xargs docker rmi cmd="cd ~ && sh deploy.sh mine" ssh -t USER_NAME@IP_ADDRESS "bash -c \"${cmd}\""
5. 编写服务器部署脚本
从上面步骤来看,我们还需要一个服务器端的部署脚本。大家可能会说,标题不是说一个脚本搞定吗?em。。。服务器一个,本地一个...简称只需一个脚本。
5.1 接收参数
在本地的构建脚本中,我们传入了docker运行的container的名字。在服务器构建脚本中需要来接收它。然后更新刚刚推送的docker image。
#!/bin/bash name=$1 docker pull detectivehlh/$name
5.2. 启动container
在启动container时我们会面对两种情况,名字为传入参数的container已经在运行了。而在此时如果再次运行 docker run
命令就会报错而导致我们无法使用最新的container,也无法达到更新应用的目的。
if docker ps | grep $name | awk {'print $(NF)'} | grep -Fx $name; then echo "Container mine is already start" docker stop $name docker rm $name docker run -d --name $name -p 3000:80 detectivehlh/$name else echo "Container mine is not start!, starting" docker run -d --name $name -p 3000:80 detectivehlh/$name echo "Finish starting" fi docker images | grep none | awk '{print $3}' | xargs docker rmi
所以在这里做一个判断,第一个if判断如果存在名字为传入参数的container正在运行,就停止当前容器再重新启动。如果不存在则直接启动容器。
run
命令就不过多解释了。 -d
表示后台运行容器并返回容器ID, --name
表示设置容器的名字, -p
表示设置端口,将阿里云服务器的3000端口映射到容器的80端口,最后一句表示要启动哪个image(好像还是解释了一遍)。
最后一句就是移除多次更新后出现的tag为 none
的无用镜像。完整的脚本如下。
#!/bin/bash name=$1 docker pull detectivehlh/$name if docker ps | grep $name | awk {'print $(NF)'} | grep -Fx $name; then echo "Container mine is already start" docker stop $name docker rm $name docker run -d --name $name -p 3000:80 detectivehlh/$name else echo "Container mine is not start!, starting" docker run -d --name $name -p 3000:80 detectivehlh/$name echo "Finish starting" fi docker images | grep none | awk '{print $3}' | xargs docker rmi
6. 如果你只是想打个包
看到标题进来的兄dei,如果只是想打包一个docker镜像,那么你只需要 Dockerfile
文件和 docker build
命令就OK了。
7. 总结
最初写这个脚本,主要目的是为了方便。所以脚本中为了达到这个目的做了一些调整。最终我达成了满足我需求的一个方便的部署脚本。
它的方便体现在,当我完成了项目代码的更新,只需要跑一下这个脚本,然后等待一会儿,项目就会自动打包成docker image,并且自动的在我的服务器上运行该container。
但是这种方式会给实际的生产环境带来一些不可控的问题。比如,脚本必须不能上传,因为涉及一些服务器的敏感信息。但是如果你不小心上传了,那你的服务器就相当于裸奔了;再比如,你对你的代码必须要十分自信,没有经过测试的代码就直接部署,会带来一些风险。
如果是自己用的,那完全不用担心,想怎么搞怎么搞。但是如果是开放给所有人用的并且有一定的访问量,比如博客,那么对于其他用户来说,这种方式就不怎么友好。
所以我的观点是,分情况来。目前来说我的项目只有少数几个人在用,也还在处于迭代阶段。并且代码仓库是私有的,所以我完全不用担心隐私的问题。服务未经测试就直接上线对于我来说,其实问题也不大。首先我会在本地测试,确认无误后才会执行部署操作。所以在不同的阶段,找到最适合自己的方案就OK。
以上所述就是小编给大家介绍的《将你的前端应用打包成docker镜像并部署到服务器?仅需一个脚本搞定》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Erupt 1.6.14 发布,零前端代码,仅需一个类文件,开发 Admin 管理后台
- Erupt 1.7.1 发布,国产、零前端代码、ADMIN 开发仅需注解、开发效率起飞
- Erupt 1.6.16 发布,零前端代码,仅需一个类文件,开发通用 Admin 管理后台
- Erupt 1.6.14 发布,国产!Admin 开发仅需注解,零前端代码,不生成代码有多爽?
- 仅需这一篇,妥妥的吃透”负载均衡”
- 仅需六步,从零实现机器学习算法!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Developing Large Web Applications
Kyle Loudon / Yahoo Press / 2010-3-15 / USD 34.99
As web applications grow, so do the challenges. These applications need to live up to demanding performance requirements, and be reliable around the clock every day of the year. And they need to withs......一起来看看 《Developing Large Web Applications》 这本书的介绍吧!