百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

将前端应用打包成docker镜像并部署?仅需一个脚本就搞定

wptr33 2024-12-10 21:20 13 浏览

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。

好了,以上就是本篇博客的全部内容

欢迎微信关注「SH的全栈笔记」,查看更多相关的文章

相关推荐

每天一个编程技巧!掌握这7个神技,代码效率飙升200%

“同事6点下班,你却为改BUG加班到凌晨?不是你不努力,而是没掌握‘偷懒’的艺术!本文揭秘谷歌工程师私藏的7个编程神技,每天1分钟,让你的代码从‘能用’变‘逆天’。文末附《Python高效代码模板》,...

Git重置到某个历史节点(Sourcetree工具)

前言Sourcetree回滚提交和重置当前分支到此次提交的区别?回滚提交是指将改动的代码提交到本地仓库,但未推送到远端仓库的时候。...

git工作区、暂存区、本地仓库、远程仓库的区别和联系

很多程序员天天写代码,提交代码,拉取代码,对git操作非常熟练,但是对git的原理并不甚了解,借助豆包AI,写个文章总结一下。Git的四个核心区域(工作区、暂存区、本地仓库、远程仓库)是版本控制的核...

解锁人生新剧本的密钥:学会让往事退场

开篇:敦煌莫高窟的千年启示在莫高窟321窟的《降魔变》壁画前,讲解员指着斑驳色彩说:"画师刻意保留了历代修补痕迹,因为真正的传承不是定格,而是流动。"就像我们的人生剧本,精彩章节永远...

Reset local repository branch to be just like remote repository HEAD

技术背景在使用Git进行版本控制时,有时会遇到本地分支与远程分支不一致的情况。可能是因为误操作、多人协作时远程分支被更新等原因。这时就需要将本地分支重置为与远程分支的...

Git恢复至之前版本(git恢复到pull之前的版本)

让程序回到提交前的样子:两种解决方法:回退(reset)、反做(revert)方法一:gitreset...

如何将文件重置或回退到特定版本(怎么让文件回到初始状态)

技术背景在使用Git进行版本控制时,经常会遇到需要将文件回退到特定版本的情况。可能是因为当前版本出现了错误,或者想要恢复到之前某个稳定的版本。Git提供了多种方式来实现这一需求。...

git如何正确回滚代码(git命令回滚代码)

方法一,删除远程分支再提交①首先两步保证当前工作区是干净的,并且和远程分支代码一致$gitcocurrentBranch$gitpullorigincurrentBranch$gi...

[git]撤销的相关命令:reset、revert、checkout

基本概念如果不清晰上面的四个概念,请查看廖老师的git教程这里我多说几句:最开始我使用git的时候,我并不明白我为什么写完代码要用git的一些列指令把我的修改存起来。后来用多了,也就明白了为什么。gi...

利用shell脚本将Mysql错误日志保存到数据库中

说明:利用shell脚本将MYSQL的错误日志提取并保存到数据库中步骤:1)创建数据库,创建表CreatedatabaseMysqlCenter;UseMysqlCenter;CREATET...

MySQL 9.3 引入增强的JavaScript支持

MySQL,这一广泛采用的开源关系型数据库管理系统(RDBMS),发布了其9.x系列的第三个更新版本——9.3版,带来了多项新功能。...

python 连接 mysql 数据库(python连接MySQL数据库案例)

用PyMySQL包来连接Python和MySQL。在使用前需要先通过pip来安装PyMySQL包:在windows系统中打开cmd,输入pipinstallPyMySQL ...

mysql导入导出命令(mysql 导入命令)

mysql导入导出命令mysqldump命令的输入是在bin目录下.1.导出整个数据库  mysqldump-u用户名-p数据库名>导出的文件名  mysqldump-uw...

MySQL-SQL介绍(mysql sqlyog)

介绍结构化查询语言是高级的非过程化编程语言,允许用户在高层数据结构上工作。它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以具有完全不同底层结构的不同数据库系统,可以使用相同...

MySQL 误删除数据恢复全攻略:基于 Binlog 的实战指南

在MySQL的世界里,二进制日志(Binlog)就是我们的"时光机"。它默默记录着数据库的每一个重要变更,就像一位忠实的史官,为我们在数据灾难中提供最后的救命稻草。本文将带您深入掌握如...