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镜像并部署到服务器?仅需一个脚本搞定的更多相关文章

  1. golang应用打包成docker镜像

    golang编译的应用是不需要依赖其他运行环境的,那么为什么还需要打包成docker镜像呢?当需要附带配置和日志等文件时可以更方便的移植和运行,下面介绍从dockerfile编译成镜像. 在项目根目录 ...

  2. SpringBoot打包成Docker镜像

    1. 本文环境 Maven:3.6.3(Maven配置参考) SpringBoot version:2.3.4.RELEASE Docker version: 19.03.11(Docker搭建参考) ...

  3. 将java项目打包成docker镜像

    简介:将jar打包成镜像好说,毕竟jar包长的都是一样的,但是我们只是写了一个普通的java项目,我也不方便封装成jar包什么的,但是我们也想打包docker image怎么办呢,我们可以用编译后的j ...

  4. 将java项目打包成docker镜像:镜像=副本

    简介:将jar打包成镜像好说,毕竟jar包长的都是一样的,但是我们只是写了一个普通的java项目,我也不方便封装成jar包什么的,但是我们也想打包docker image怎么办呢,我们可以用编译后的j ...

  5. IDEA中直接将 SpringBoot项目打包成 Docker镜像时 pom.xml的配置

    <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactI ...

  6. JAVA SpringBoot 项目打包(JAR),在打包成 docker 镜像的基本方法

    1,打包 SpringBoot 项目,使用 IDEA 如下图 2,将 JAR 包上传到安装了 Docker 的 linux 服务器上,并且在相容目录下创建一个名为 Dockerfile 的文件 3,在 ...

  7. 【Docker】Maven打包SpringBoot项目成Docker镜像并上传到Harbor仓库(Eclipse、STS、IDEA、Maven通用)

    写在前面 最近,在研究如何使用Maven将SpringBoot项目打包成Docker镜像并发布到Harbor仓库,网上翻阅了很多博客和资料,发现大部分都是在复制粘贴别人的东西,没有经过实践的检验,根本 ...

  8. 操作系统-容器-Docker:如何将应用打包成为 Docker 镜像?

    ylbtech-操作系统-容器-Docker:如何将应用打包成为 Docker 镜像? 1.返回顶部 1. 虽然 DockerHub 提供了大量的镜像,但是由于企业环境的多样性,并不是每个应用都能在 ...

  9. BI系统打包Docker镜像及部署的技术难度和实现

    BI系统打包Docker镜像及部署的技术难度和实现 随着容器化技术盛行,Docker在前端领域也有着越来越广泛的应用:传统的前端部署方式需要我们将项目打包生成一系列的静态文件,然后上传到服务器,配置n ...

随机推荐

  1. java基础小项目练习之1----3天做出飞机大战

    Shoot射击游戏第一天一. 关键问题(理论):1. 简述FlyingObject.Enemy.Award.Airplane.Bee.Bullet.Hero之间的继承与实现关系2. 简述Hero类构造 ...

  2. 【NOI赛前训练】——专项测试1·网络流

    T1: 题目大意: 传送门 给一个长度为$n(n<=200)$的数列$h$,再给$m$个可以无限使用的操作,第$i$个操作为给长度为花费$c_i$的价值给长度为$l_i$的数列子序列+1或-1, ...

  3. 【构造】UVa 11387 The 3-Regular Graph

    Description 输入n,构造一个n个点的无向图,使得每个点的度数都为3.不能有重边和自环,输出图或确定无解. Solution 如果n为奇数,奇数*3=奇数,度数为奇,必无解. 考虑我们怎么构 ...

  4. 【爆料】-《西悉尼大学毕业证书》UWS一模一样原件

    ☞西悉尼大学毕业证书[微/Q:865121257◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归&a ...

  5. LSTM实现中文文本情感分析

    1. 背景介绍 文本情感分析是在文本分析领域的典型任务,实用价值很高.本模型是第一个上手实现的深度学习模型,目的是对深度学习做一个初步的了解,并入门深度学习在文本分析领域的应用.在进行模型的上手实现之 ...

  6. Vue之生命周期函数和钩子函数详解

    在学习vue几天后,感觉现在还停留在初级阶段,虽然知道怎么和后端做数据交互,但是对对vue的生命周期不甚了解.只知道简单的使用,而不知道为什么,这对后面的踩坑是相当不利的.因为我们有时候会在几个钩子函 ...

  7. Shell中去除字符串前后空格的方法

    [root@local ~]# echo " A BC " A BC [root@local ~]# eval echo " A BC " A BC 或者 [r ...

  8. MTCNN算法与代码理解—人脸检测和人脸对齐联合学习

    目录 写在前面 算法Pipeline详解 如何训练 损失函数 训练数据准备 多任务学习与在线困难样本挖掘 预测过程 参考 博客:blog.shinelee.me | 博客园 | CSDN 写在前面 主 ...

  9. 分享 Xamarin.android 关于使用SQLiteOpenHelper的小白经验

    关于使用SQLiteOpenHelper的使用,对于小白的我,百度啦相当多的大神的介绍,均未能让我这新手(零基础)成功学会,参考了http://www.cnblogs.com/yaozhenfa/p/ ...

  10. 如何购买并配置linux服务器上的数据库

    首先百度搜索阿里云 如果是学生可以学生认证 然后注册账号->个人认证->学生认证 然后你会发现 服务器一年只要114,114你买不了上当,买不了吃亏,买下面的ECS服务器,系统可以选择wi ...