将你的前端运用打包成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。

    原文作者:detectiveHLH
    原文地址: https://segmentfault.com/a/1190000018959748
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞