zoukankan      html  css  js  c++  java
  • Docker 建站小记

    一,前言

    Docker 建站小记,我使用了四个镜像来搭建:nginx,certbot,mysql,gradle。欢迎访问:https://www.zzk0.top

    这个网页是从 github 上找的个人主页,背景用的是 bing 的壁纸,中间有两个链接,一个指向我的 github,一个指向博客园。后端项目目前只有一个接口,当有人访问这个网站的时候,就会向后端项目发出一个请求,由 nginx 负责将对 api.zzk0.top 的请求转发到后端项目。

    最理想的状态是,我直接 docker-compose up,我就可以将项目运行起来了。不过我的方法,需要自己手动配置一下才行,一个是初始化申请 SSL 的脚本,一个是定时分割 NGINX 日志。之后就只需要 docker-compose up 就行了。

    这里简单讲讲这四个镜像分别是干什么的吧。

    • nginx,这个是 http 服务器,用来提供提供静态资源的,这篇博客大部分内容都是在讲如何配置 nginx。
    • certbot,这个用来申请 SSL 证书。设置了一个定时任务,每个月刷新一下证书。
    • mysql,后端项目数据库。
    • gradle,编译并运行 springboot 项目。

    二,NGINX

    重新加载配置

    修改了 NGINX 的配置,但是又不想重新启动容器。我们可以通过向容器发送命令来加载新配置。

    # docker exec -it your-name nginx -s reload
    2021/01/23 02:30:58 [notice] 23#23: signal process started
    

    HTTPS 配置

    首先我们需要证书和密钥,我们可以使用免费的 Let's Encrypt 来生成,不过三个月就会过期,所以需要刷新一下。

    证书的生成可以选择在本机上还是在 Docker 里,如果在本机上生成,我们可以选择 standalone 模式,但是这样的话,它需要短暂占用一下 80 端口来验证这个域名是否是你的。因此当你有一个正在运行的 NGINX 并且占用了 80 端口的话,我们需要去暂停它。如果在 Docker 中生成,并且你的网站有一个根目录,那么可以使用 webroot 模式,它会在你的网站根目录下生成一些文件,然后通过域名去访问它来验证这个域名是不是你的,使用 webroot 模式就不需要暂停 NGINX,因此对正在运行的网站影响会小一些。

    选择前者的好处是,不需要定制 Docker,但是需要短暂停止服务器;选择后者的好处是,不需要停止服务器,可移植性更好一点,本机只需要有 Docker 就能跑,但是需要定制镜像比较麻烦。不过,这种比较常见的需求,我们上 docker hub 搜一搜,一找就有了:https://hub.docker.com/r/staticfloat/nginx-certbot/ 。再搜一搜,我们会发现另一个方案:为什么不搞一个 certbot 的容器呢?然后将 nginx 的容器和 certbot 的容器连接起来!好,那我们就加多一个容器,来帮我们生成 SSL 证书好了。

    申请

    这篇文章可以参考看看 certbot 的操作。这篇文章提供了 certbot 和 nginx 的方案。

    从文章配套的 Github 仓库 中把它的脚本和配置文件复制粘贴过来,把所有的 example.org 域名改成自己的域名,然后运行它的脚本。如果失败了,建议检查一下是不是 NGINX 没有启动。这个脚本不会提醒你 NGINX 没有启动,如果失败了,很有可能是 NGINX 没有配置好。

    一开始跑这个脚本,我失败了几次。之后逐步执行脚本,然后启动容器看看什么问题。一看,才知道原来是 https 的推荐参数文件没有下载好,所以手动下载了那几个文件,然后修改脚本为复制而不是下载。

    重定向

    nginx 将 http 重定向到 https,完整的配置文件可以看附录。

    server {
        listen 80;
        server_name zzk0.top www.zzk0.top;
        server_tokens off;
    
        location /.well-known/acme-challenge/ {
            root /var/www/certbot;
        }
    
        location / {
            return 301 https://$host$request_uri;
        }
    }
    
    server {
        listen 443 ssl;
        server_name zzk0.top www.zzk0.top;
        root /var/www/html;
        server_tokens off;
    
        ssl_certificate /etc/letsencrypt/live/zzk0.top/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/zzk0.top/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
        location / {
            try_files $uri $uri/ =404;
        }
    }
    

    配置子域名

    假设有一个域名 test.com,我们需要将对 api.test.com 的请求转发到 Tomcat,对 test.com 的请求则直接提供静态网站。

    这个需求比较简单,在 server 下面设置好 server_name 就可以了。另外,我们还需要注意不要让别人用 ip 访问我们的网站,网上的说法是,别人可以恶意使用未备案的域名指向这个 ip,然后导致网站被封掉了。

    server {
        listen 80 default_server;
        server_name _;
        return 403;
    }
    
    server {
        listen 443 default_server;
        server_name _;
        ssl_certificate /etc/letsencrypt/live/zzk0.top/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/zzk0.top/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
        return 403;
    }
    

    访问日志

    为了记录网站的访问记录,可以使用 NGINX 的访问日志来做记录,按天分割。NGINX 的镜像里面没有 crontab,所以这里就用主机来做。方法是每天定时将文件重命名,然后 reload NGINX。不过这个部分比较不智能,每次更换主机的时候,都需要手动去配置,还需要修改下面的路径。

    #!/bin/sh
    
    LOGS_PATH=/root/home/data/nginx
    TODAY=$(date -d 'today' +%Y-%m-%d)
    
    mv ${LOGS_PATH}/error.log ${LOGS_PATH}/error_${TODAY}.log
    mv ${LOGS_PATH}/access.log ${LOGS_PATH}/access_${TODAY}.log
    
    docker exec -i home-nginx nginx -s reload
    

    接下来,将以下内容加入到 /etc/crontab 中,这样就可以执行每日任务了。每天凌晨4点的时候,自动分割日志。

    0 4 * * * root /root/home/nginx/daily_log.sh >> /root/home/data/nginx/daily_log.log 2>&1
    

    三,MySQL

    有时候我们需要进入数据库的镜像里面去看看数据。

    # 进入镜像
    docker exec -it your-name bash
    
    # 登录
    mysql -uroot -p
    
    # 罗列数据库
    show database
    

    四,后端项目

    后端项目使用 SpringBoot 来做。需求是:启动 Docker 后构建源码并运行。这个部分使用 gradle 的镜像,启动的时候,运行 gradle bootRun 就可以了。

    当我们更新了后端项目之后,我们只需要重启这个容器,就可以构建了。我的后端项目容器名字叫做 springboot,重启一下就可以将接口更新了,不过重启过程中的请求会失败。

    docker restart springboot
    

    下面是 docker-compose.yml 中的配置。

    web:
        container_name: springboot
        restart: always
        image: gradle:6.7.1-jdk8
        depends_on:
          - db
        volumes:
          - ./api:/home/gradle/project
        environment:
          TZ : 'Asia/Shanghai'
        command: bash -c "cd /home/gradle/project && gradle bootRun"
    

    附录

    NGINX 配置

    user  nginx;
    worker_processes  1;
    
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    
    events {
        worker_connections  1024;
    }
    
    
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    	upstream tomcat {
    		server web:8080;
    	}
    
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
        access_log  /var/log/nginx/access.log  main;
    
        limit_req_zone $binary_remote_addr zone=api_limit_req:10m rate=30r/m;
    
        sendfile        on;
        keepalive_timeout  65;
        gzip  on;
        include /etc/nginx/conf.d/*.conf;
    
        # forbid access via ip address
        server {
            listen 80 default_server;
            server_name _;
            return 403;
        }
    
        server {
            listen 443 default_server;
            server_name _;
            ssl_certificate /etc/letsencrypt/live/zzk0.top/fullchain.pem;
            ssl_certificate_key /etc/letsencrypt/live/zzk0.top/privkey.pem;
            include /etc/letsencrypt/options-ssl-nginx.conf;
            ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
            return 403;
        }
    
        # configure zzk0.top, redirect to https and serve static files
        server {
            listen 80;
            server_name zzk0.top www.zzk0.top;
            server_tokens off;
    
            location /.well-known/acme-challenge/ {
                root /var/www/certbot;
            }
    
            location / {
                return 301 https://$host$request_uri;
            }
        }
    
        server {
            listen 443 ssl;
            server_name zzk0.top www.zzk0.top;
            root /var/www/html;
            server_tokens off;
    
            ssl_certificate /etc/letsencrypt/live/zzk0.top/fullchain.pem;
            ssl_certificate_key /etc/letsencrypt/live/zzk0.top/privkey.pem;
            include /etc/letsencrypt/options-ssl-nginx.conf;
            ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
            location / {
                try_files $uri $uri/ =404;
            }
        }
    
        # configure api.zzk0.top, backend api
        server {
            listen 80;
            server_name api.zzk0.top;
            server_tokens off;
    
            location /.well-known/acme-challenge/ {
                root /var/www/certbot;
            }
    
            location / {
                return 301 https://$host$request_uri;
            }
        }
    
        server {
            listen 443 ssl;
            server_name api.zzk0.top;
            server_tokens off;
    
            ssl_certificate /etc/letsencrypt/live/zzk0.top/fullchain.pem;
            ssl_certificate_key /etc/letsencrypt/live/zzk0.top/privkey.pem;
            include /etc/letsencrypt/options-ssl-nginx.conf;
            ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
            location / {
                limit_req zone=api_limit_req;
                proxy_pass http://tomcat;
                proxy_set_header    Host                $http_host;
                proxy_set_header    X-Real-IP           $remote_addr;
                proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
            }
        }
    
    }
    

    Docker 配置

    version: '3'
    services:
      certbot:
        container_name: home-certbot
        restart: always
        image: certbot/certbot
        volumes:
          - ./data/certbot/conf:/etc/letsencrypt
          - ./data/certbot/www:/var/www/certbot
        entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 720h & wait $${!}; done;'"
    
      nginx:
        container_name: home-nginx
        restart: always
        image: nginx:1.18.0
        ports:
          - 80:80
          - 443:443
        depends_on:
          - web
        links:
          - web:web
        environment:
          TZ : 'Asia/Shanghai'
        volumes:
          - ./html:/var/www/html
          - ./nginx/nginx.conf:/etc/nginx/nginx.conf
          - ./data/certbot/conf:/etc/letsencrypt
          - ./data/certbot/www:/var/www/certbot
          - ./data/nginx:/var/log/nginx
        command: "/bin/sh -c 'while :; do sleep 720h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"'"
    
      db:
        container_name: home-db
        restart: always
        image: mysql:8.0.13
        ports:
          - 7706:3306
        volumes:
          - ./data:/var/lib/mysql
        environment:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: backend_database
          MYSQL_USER: root
          MYSQL_PASSWORD: root
    
      web:
        container_name: springboot
        restart: always
        image: gradle:6.7.1-jdk8
        depends_on:
          - db
        volumes:
          - ./api:/home/gradle/project
        environment:
          TZ : 'Asia/Shanghai'
        command: bash -c "cd /home/gradle/project && gradle bootRun"
    
  • 相关阅读:
    1052 卖个萌
    编程实现hdfs对文件的操作
    关于Eclipse编译运行MapReduce程序报错问题的解决
    用户模板和用户场景
    用户体验评价
    大二下学期软件工程课程总结
    教师派第二阶段10
    教师派第二阶段09
    教师派第二阶段07
    教师派第二阶段06
  • 原文地址:https://www.cnblogs.com/zzk0/p/14318711.html
Copyright © 2011-2022 走看看