• 前端项目的Docker镜像打包


    对读者的要求

    • 掌握nginx基本用法
    • 掌握Docker基础用法
    • Linux 命令行基本操作(Windows下则是掌握git bash这个工具)

    简介

    所有的项目最终都要布署到线上才能对外提供服务,在布署方案上,之前主要采用git拉取的方式,而现在则主要使用docker直接启动镜像的方式,或者通过云容器k8saws ecs启动镜像。不论哪一种方式,项目的Docker镜像制作都是必要的。后端为主的项目和纯前端的Docker镜像制作流程是一样的,但是在配置上后端会复杂一些。因此分开讨论,本文只谈前端项目的镜像制作。

    为方便讨论,本文所指的前端项目,本文使用umijs的脚手架创建的前端项目,用于演示下面的步骤。读者使用相同的脚本架基本上直接拷贝代码就能使用。

    最后达到的效果应该是用户在任何一台机器上,直接执行下面的命令,启动镜像就能完成布署:

    docker run -p 8080:80 pheye/demo-app:latest
    

    步骤

    创建镜像文件

    在前端工程目录下,创建Dockerfile文件

    FROM nginx:alpine
    MAINTAINER LIUWENCAN <phenye@gmail.com>
    RUN adduser -D -H -u 5000 -s /bin/sh www
    RUN rm /etc/nginx/conf.d/default.conf
    ADD scripts/nginx.conf /etc/nginx/
    ADD scripts/app.conf /etc/nginx/sites-available/
    ADD dist /var/www
    VOLUME /var/www
    CMD ["nginx"]
    

    这里面会将dist目录、scripts/nginx.confscripts/app.conf这2个nginx配置文件添加到镜像中。

    create-react-app默认输出的目录叫build,请改为dist目录

    其中,dist目录是通过npm run build生成的。而scripts/nginx.conf是一个全局的nginx,是很固定的,主要是做打开gzip压缩、设置日志格式等等,与本教程关系不大,因此直接查看附录将文件拷贝过去即可。

    scripts/app.conf才是应用的配置文件,直接见下面配置,特别需要注意的是/api这一节,它对应到前端在调试时使用的反向代理配置,如果不需要可直接忽略。

    server {
        listen 80;
    
        root /var/www;
    
        location ~* .*.(gif|jpg|jpeg|png|bmp|swf|js|css)$ {
          expires 30d;
        }
    
        location / {
            # 用于配合 browserHistory使用
            try_files $uri $uri/ /index.html;
        }
    
        location /api {
            proxy_pass http://172.16.3.100:9200;
            proxy_set_header   X-Forwarded-Proto $scheme;
            proxy_set_header   X-Real-IP        $remote_addr;
        }
    
    }
    

    构建镜像

    docker build -t demo-app:latest .
    

    测试镜像

    docker run -p 80:80 demo-app:latest
    

    正常启动后,在浏览器中输入http://127.0.0.1/确认下镜像是否正常工作。

    推送镜像

    完成测试以后,要将镜像推送到公共的镜像仓库,然后在服务器上再拉取下来。一般来说,如果是可公开的,推送到Docker Hub就完事了。

    docker tag demo-app:latest pheye/demo-app:latest
    docker push pheye/demo-app:latest
    

    但是在公司里面,一般都是要推送到私有镜像仓库,可选择阿里云镜像仓库、AWS ECR,或者在内网自建镜像仓库都行。本文以阿里云为例演示推送

    # 登陆阿里云镜像仓库
    username=${ALIYUN_REGISTRY_USERNAME}
    pwd=${ALIYUN_REGISTRY_PASSWORD}
    docker login --username=$username -p $pwd registry.cn-hangzhou.aliyuncs.com
    
    # 修改TAG并推送
    docker tag demo-app:latest registry.cn-hangzhou.aliyuncs.com/phenye/demo-app:latest
    docker push registry.cn-hangzhou.aliyuncs.com/phenye/demo-app:latest
    

    推送镜像以后,再登陆其他的机器VPS,直接按照“简介”中的方式,启动镜像应该能正常访问。

    优化流程

    前面的示例,总是打包成demo-app:latest,版本号总是latest,这种方式在生产方式下一旦出问题是没办法回滚的。实际使用场景通常是跟CI/CD结合,以每个git commit作为版本号,有问题的时候就回滚。因此构建和推送都要支持版本号,每次都手动敲命令很麻烦。可以增加两个脚本优化这个流程:

    优化构建

    创建scripts/build.sh文件:

    #!/bin/sh
    
    if [ $# -gt 1 ] ; then
    docker build -t demo-app:$1 -t  demo-app:latest  .
    else
    docker build -t  demo-app:latest  .
    fi
    

    构建镜像,要指定版本时,就执行如下命令:

    ./scripts/build.sh v1.0.0
    

    优化推送

    创建./scripts/push.sh

    #!/bin/sh
    
    pwd=${ALIYUN_REGISTRY_PASSWORD}
    docker login --username=phenye -p $pwd registry.cn-hangzhou.aliyuncs.com
    docker tag demo-app:latest registry.cn-hangzhou.aliyuncs.com/phenye/demo-app:latest
    docker push registry.cn-hangzhou.aliyuncs.com/phenye/demo-app:latest
    
    
    if [ $# -gt 0 ] ; then
      tag=$1
      docker tag demo-app:latest registry.cn-hangzhou.aliyuncs.com/phenye/demo-app:${tag}
      docker push registry.cn-hangzhou.aliyuncs.com/phenye/demo-app:${tag}
    fi
    

    要在推送时指定版本号,就使用如下命令

    ./scripts/push.sh v1.0.0
    

    附录

    工程目录结构

    为便于讨论,列出工程目录结构,方案在后续章节出现的文件,如果不知道它们应该放哪里,可参照这个工程目录结构。

    .
    ├── Dockerfile
    ├── dist/
    ├── pages/
    │   ├── index.css
    │   └── index.js
    └── scripts/
        ├── app.conf
        ├── build.sh
        ├── nginx.conf
        └── push.sh
    

    nginx配置

    nginx.conf并不是必须的,它主要做开启压缩、配置日志等操作,是一些全局的配置。

    user www;
    worker_processes 4;
    pid /run/nginx.pid;
    daemon off;
    
    events {
      worker_connections  2048;
      multi_accept on;
      use epoll;
    }
    
    http {
      server_tokens off;
      sendfile on;
      tcp_nopush on;
      tcp_nodelay on;
      keepalive_timeout  600;
      fastcgi_read_timeout 300;
      types_hash_max_size 2048;
      client_max_body_size 20M;
      server_names_hash_bucket_size 256;
      include /etc/nginx/mime.types;
      default_type application/octet-stream;
    
      gzip on;
      gzip_disable "msie6";
      gzip_min_length 1k;
      gzip_comp_level 1;
      gzip_vary on;
      gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
    
      ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
      ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    
      log_format access  '$http_x_forwarded_for $remote_addr [$time_local] "http://$host" "$request" '
                  '$status $body_bytes_sent "$http_referer" "$http_user_agent" "$remote_user" ';
    
      log_format main   '{"@timestamp":"$time_iso8601",'
                            '"@source":"$server_addr",'
                            '"hostname":"$hostname",'
                            '"ip":"$http_x_forwarded_for",'
                            '"client":"$remote_addr",'
                            '"request_method":"$request_method",'
                            '"scheme":"$scheme",'
                            '"domain":"$server_name",'
                            '"referer":"$http_referer",'
                            '"request":"$request_uri",'
                            '"args":"$args",'
                            '"size":$body_bytes_sent,'
                            '"status": $status,'
                            '"responsetime":$request_time,'
                            '"upstreamtime":"$upstream_response_time",'
                            '"upstreamaddr":"$upstream_addr",'
                            '"http_user_agent":"$http_user_agent",'
                            '"https":"$https"'
                            '}';
      access_log /dev/stdout main;
      error_log /dev/stderr;
      include /etc/nginx/conf.d/*.conf;
      include /etc/nginx/sites-available/*.conf;
      open_file_cache off; # Disabled for issue 619
      charset UTF-8;
    }
    
  • 相关阅读:
    springboot对JPA的支持
    Hibernate-什么是orm思想
    利用Struts拦截器完成文件上传功能
    Struts2的CRUD
    struts2的初步认识
    Maven搭建
    java虚拟机
    Map集合
    Set集合(TreeSet)
    Set集合的
  • 原文地址:https://www.cnblogs.com/pheye/p/12844407.html
Copyright © 2020-2023  润新知