文章主要记录一下如何实现项目的自动化集成部署,并且让docker容器支持HTTPS的访问,并且通过几个例子来实践。这也是我目前觉得服务端比较好的架构思路了

解决哪些痛点问题

在个人开发项目的时候,我们希望自己写的项目网站能放到有公网IP的服务器上供每个人都可以浏览访问,但是服务器端通常会遇到一些问题:

端口问题:

比如A项目需要占用3000端口,B项目也需要,这个时候导致端口的冲突,就需要修改端口。而且记住端口也是一件很麻烦的事情,容易导致端口冲突问题。(本文只需要服务器开放80和443端口,通过ngixn代理其他docker容器,从而无需开启其他端口就可以访问到容器应用)

部署问题:

每次项目代码的小改动,都需要重新本地构建,连接服务器上传代码,这是非常麻烦的一件事情。(通过Jenkins自动化集成部署可以解决该问题)

HTTPS证书问题:

每个项目需要域名访问,比如api.admin.com对应的是api接口项目,front.admin.com对应前端项目,但是证书需要为每个域名单独申请,这就很费时费力了,而且每个证书都有时效性的,过期就需要手动更新,很麻烦(通过acme可以自动更新证书,并且是免费开源的)

碎片化:

服务器端存放的会比较碎片化,安装的软件会比较杂,容易导致软件之间的冲突,比如服务器安装的node环境是14,其中一个项目只能在node14才可以正常运行,另外一个则需要在node20环境才可以,或者一个项目放在微信云服务上,另外一个存放在某静态存放网站,这样有可能导致跨域问题,域名也无法统一。(使用一台服务器,利用Docker的隔离性恰好可以解决这个问题)

以上这些痛点问题,本文会搭建一个在服务端持续集成持续部署的环境,并使用Nginx代理支持https的访问。

服务端整体的架构与思路

在开始搭建之前,有必要先看一下服务端整体的架构图,了解一下在干什么,为什么要这么做,这么做的目的是什么:

先来看下流程:

  • 用户通过www.example.comapi.example.com或者blog.example.com等二级域名访问服务
  • DNS服务器(DNSpro、cloudflare)解析这个网址到指定服务器的IP地址上的80端口
  • Nginx接收到这个请求,通过conf配置文件,在内网里面找到这个Docker容器服务,并访问这个Docker容器(这个过程中,Nginx已经通过配置文件给链接加上https证书加密)
  • Docker容器返回给NginxNginx再通过443端口返回给用户。

在整个过程中,服务器只是开放80和443端口,Docker容器无需对外开放端口,Docker容器之间通过内网段通讯,互不干扰

准备

在开始之前,我们需要准备一下环境:

  • 一台初始化的centos7.8系统服务器(避免软件安装冲突)
  • 一个已经备案的域名(国内服务器域名需要备案)

服务器连接配置

修改默认端口:

连接服务器:

1
ssh root@you ip

修改端口,编辑sshd_config文件:

1
vi /etc/ssh/sshd_config

输入 i 编辑,把#去掉,把22改为想要的端口,最后:wq保存:

1
Port 10024

然后需要执行这一句命令:(端口是刚才修改的端口)

1
semanage port -a -t ssh_port_t -p tcp 10024

可能会得到一个错误,可以执行一下下面这句:

1
yum whatprovides semanage
1
yum install -y  policycoreutils-python

最后再重新执行:

1
semanage port -a -t ssh_port_t -p tcp 10024

查看SSH运行的端口:(不是必须执行)

1
semanage port -l | grep ssh

删除SSH端口:(不是必须执行)

1
semanage port -d -t ssh_port_t -p tcp 22 

重启SSH

1
service sshd restart

重新连接服务器:(端口是刚才的端口)

1
ssh -p 10024 root@your ip

密钥方式连接服务器:

在本地电脑生成SSH Key,一直回车就可以:

1
ssh-keygen

在本地路径C:\Users\你的用户\.ssh下创建config文件:

1
2
3
4
5
6
Host Test
Port #端口号
HostName #IP地址
User root
IdentityFile #本地id_rsa文件
IdentitiesOnly yes

服务器cd ~/.ssh/目录,(一定要CD到这个目录,切勿直接在根目录直接使用下面命令,会导致这个文件不生效)编辑文件,到本地C:\Users\你的用户名\.ssh 找到公钥文件,把本地电脑的公钥文件id_rsa.pub复制进去,:wq保存:

1
vi authorized_keys

如果之前连接过服务器,格式化后再连接可能报错,可以先删除本地电脑这两个文件,这两个文件是历史连接的记录

至此,完成服务器的端口修改和使用密钥登录的操作

旧版安装docker

这个办法适合境外服务器操作,因为2024年6月初的时候,Docker的镜像无法正常pull了,所以按照这个办法会出现报错等问题,不推荐;(有新版的安装方式下面介绍)

该内容步骤具体可以参考:https://www.toimc.com/docker%E5%85%A5%E9%97%A8%E4%B9%8B%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/

  1. 先删除旧的版本(如果没有可以跳过):

    1
    2
    3
    4
    5
    6
    7
    8
    sudo yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine
  2. 安装必须的依赖:

    1
    2
    3
    sudo yum install -y yum-utils \
    device-mapper-persistent-data \
    lvm2

    添加stable的Docker-ce的源:

    1
    2
    3
    sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
  3. 安装docker-ce:

    1
    sudo yum install docker-ce docker-ce-cli containerd.io
  4. 启动服务:

    1
    sudo systemctl start docker

docker-compose安装:

Docker-Compose工具是一个批量工具,用于运行与管理多个docker容器。官方文档:Install Docker Compose

1
2
3
4
5
6
7
8
9
# 下载docker-compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 给予执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 测试命令
docker-compose --version
docker-compose version 1.23.2, build 1110ad01

新版安装docker

由于不可抗力原因,截至目前,2024年6月27号,阿里云的服务器是无法正常拉取docker镜像的,以下是阿里云售后技术的回复:

您好,近期因为https://hub.docker.com/ 被污染(具体可以参考:https://boce.aliyun.com/home) timeout等现象, 关于解决方案

1、针对个人单docker环境客户

1.1 本地先pull下来(因为域名被污染,本地可能也无法拉取,可以考虑中国香港或者是海外的服务器pull下来)

1.2 使用docker save导出为tar.gz文件,然后上传到自己的机器,使用docker load -i XXX.tar.gz解压出来使用 导出命令: docker save -o nginx.tar.gz nginx:latest 导入命令: docker load -i nginx.tar.gz

2、针对集群用户

2.1 本地先pull下来(因为域名被污染,本地可能也无法拉取,可以考虑中国香港或者是海外的服务器pull下来)

2.2 修改tag 命令(例如): docker tag nginx:latest ceshi:latest 2.3 然后上传到阿里云acr 容器镜像仓库里面,yaml地址里面修改为您阿里云仓库的vpc地址,用私网拉取,比走海外公网的速率高以及稳定性强一点 注意:如果您的集群或者是ACR是大陆的,可能会存在链路问题导致镜像推送到ACR失败,建议导出镜像后导入镜像到您本地的大陆机器,然后push到您的ACR里边

所以现在安装Docker如果按照之前的方式会出现无法正常安装的情况,Docker也无法正常的pull镜像,这里有两种解决方法:(当然方法不止这两种)

  1. 使用境外的服务器,把镜像pull到本地,然后再上传到服务器,优点是简单粗暴,原理简单。缺点是要下载镜像有限,只能先下载需要用到的镜像。(我采用的是这种方式)
  2. 使用cloudflare和这个开源项目https://github.com/cmliu/CF-Workers-docker.io/issues/8 ,原理就是使用cloudflare去代理dockerhub这个网站,这样就可以访问到dockerhub。配置起来很简单,具体可以看看这个UP主,讲解得比较简单明了:https://www.bilibili.com/video/BV1H442197oQ/

这里是centos7.8的安装步骤:

  1. 运行以下命令,下载docker-ceyum源。

    1
    sudo wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  2. 运行以下命令,安装Docker。

    1
    sudo yum -y install docker-ce
  3. 执行以下命令,检查Docker是否安装成功。

    1
    docker -v
  4. 如下图回显信息所示,表示Docker已安装成功。

  5. 执行以下命令,启动Docker服务,并设置开机自启动。

    1
    2
    sudo systemctl start docker 
    sudo systemctl enable docker
  6. 执行以下命令,查看Docker是否启动。

    1
    sudo systemctl status docker

安装docker-compose:(centos7.8不推荐使用,在一些场景会报错,推荐适用老版本的安装方式)

  1. 运行以下命令,安装setuptools

    1
    sudo pip3 install -U pip setuptools
  2. 运行以下命令,安装docker-compose

    1
    sudo pip3 install docker-compose
  3. 运行以下命令,验证docker-compose是否安装成功。(这里会提示一个警告,可以忽略,大概意思就是python版本太低,)

    1
    docker-compose --version

docker的安装具体参考阿里云:https://help.aliyun.com/zh/ecs/use-cases/install-and-use-docker-on-a-linux-ecs-instance

安装acme

acme官网Githubhttps://github.com/acmesh-official/acme.sh

首先确认您域名使用的DNS服务商,不同的DNS服务商对应的命令是不同的。比如这里使用的腾讯云的DNSPro解析域名服务。

安装:(这里一定要带上自己的邮箱,否则后面会报错,会有记录报错,需要多试几次)

1
curl https://get.acme.sh | sh -s email="[email protected]"

这个命令安装acme并且创建了一个 cronjob, 每天 0:00 点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书.

注意:安装好之后建议重新连接服务期,如果这个时候直接使用acme.sh可能有问题

生成证书

下面是示例的讲解:

生成证书:(这里我们使用DNSAPi的高阶用法生成证书)

更高阶的用法:https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert

DNS APihttps://github.com/acmesh-official/acme.sh/wiki/dnsapi

以下是cloudflare的生成证书方式:(cloudflareDNS有个坑,后面介绍)

1
2
3
export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
export CF_Email="[email protected]"
acme.sh --issue --dns dns_cf -d example.com -d *.example.com

以下是DNSPro的生成证书方式:(注意申请的是DNSPro的令牌不是腾讯云的令牌)

1
2
3
export DP_Id="XXXX"
export DP_Key="XXXXXXXXXXXXX"
acme.sh --issue --dns dns_dp -d example.top -d *.example.top

至此,证书签发完成。

安装Nginx容器

流程梳理

  1. 创建home/keys文件夹,存放Https证书文件
  2. 创建随机的密钥
  3. 创建容器的局域网段https
  4. 创建/home/keys/nginx/conf.d文件夹,存放nginx的配置文件
  5. 创建nginx.conf文件,并上传到服务器home/nginx文件夹下
  6. 通过docker-cpmpose文件安装Nginx
  7. 最后执行acme.sh命令

Tip:把所有的配置文件都放在home文件夹下,方便以后管理,目录使用英文并具有一定意义

Https文件存放

按照上面的流程,我们需要把https证书放到一个可以让nginx容器访问到的地方,这是一个官方的示例:

1
2
3
4
acme.sh --install-cert -d example.top \
--key-file /path/to/keyfile/in/nginx/key.pem \
--fullchain-file /path/to/fullchain/nginx/cert.pem \
--reloadcmd "service nginx force-reload"

(一个小提醒, 这里用的是 service nginx force-reload, 不是 service nginx reload, 据测试, reload 并不会重新加载证书, 所以用的 force-reload)

因为我们使用的是Docker的方式安装Nginx,所以我们需要修改一下,把目录都放到home目录的key文件夹下(记得域名改为自己的)

创建文件夹:mkdir /home/keys,存放Https证书文件,这一步只需要创建文件夹,无需执行命令,最后再执行。

1
2
3
4
acme.sh --install-cert -d example.top \
--key-file /home/keys/key.pem \
--fullchain-file /home/keys/cert.pem \
--reloadcmd "docker restart some-nginx"

这句命令主要为域名创建了两个证书文件,并放在key指定文件夹下,最后重启some-nginx容器

创建随机的密钥

  • 创建随机的https证书密钥:

    1
    openssl dhparam -out /home/keys/dhparam.pem 2048

创建容器的局域网段

创建容器的局域网段https:

1
2
3
4
5
6
# 创建容器的局域网段https
docker network create https
#这是查询network有哪些网段
docker network ls
#这是查询network里面https网段里面有哪些容器加入进来
docker network inspect https

nginx的配置文件存放

  • 创建文件夹:

    1
    2
    mkdir /home/nginx
    mkdir /home/nginx/conf.d

创建nginx.conf文件

  • 创建nginx.conf文件,并上传到服务器home/nginx文件夹下,这是一个通用的文件配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    user nginx;
    worker_processes auto;
    pid /run/nginx.pid;
    worker_rlimit_nofile 65535;
    events {
    # 设置事件驱动模型,是内核2.6以上支持
    use epoll;
    worker_connections 65535;
    accept_mutex off;
    multi_accept off;
    }

    http {
    # Basic Settings
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    send_timeout 120;
    keepalive_timeout 300;
    client_body_timeout 300;
    client_header_timeout 120;

    proxy_read_timeout 300;
    proxy_send_timeout 300;
    #tcp_nopush on;
    types_hash_max_size 4096;
    client_header_buffer_size 16m;
    client_max_body_size 4096m;

    include /etc/nginx/mime.types;
    include /etc/nginx/conf.d/*.conf;
    # include /usr/share/nginx/modules/*.conf;

    default_type application/octet-stream;
    # Logging Settings
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
    # 开启gzip
    gzip on;
    # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
    gzip_min_length 1k;
    # gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
    gzip_comp_level 2;
    # 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
    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 font/ttf font/otf image/svg+xml;
    # 是否在http header中添加Vary: Accept-Encoding,建议开启
    gzip_vary on;
    # 禁用IE 6 gzip
    gzip_disable "MSIE [1-6]\.";
    }

安装Nginx

  • 接下来是Nginx容器安装,编写docker-compose文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: "3"
services:
web:
image: nginx:latest
container_name: "some-nginx"
restart: always
volumes:
- /home/nginx/nginx.conf:/etc/nginx/nginx.conf
- /home/nginx/conf.d:/etc/nginx/conf.d
- /home/keys:/home/keys
# blog
- /home/blog:/var/www
ports:
- "80:80"
- "443:443"

# docker network create https
networks:
default:
external:
name: https

解释:创建了一个some-nginx的容器,把容器文件nginx.confconf.d和keys文件夹挂载出来。暴露端口是80和443;把容器加入到https的网段里面,让这个网段里面的容器可以被nginx容器代理到。

编写好后就可以直接使用一下命令安装:

1
docker-compose up -d

执行acme.sh命令

最后我们就可以运行之前acem的安装命令:

1
2
3
4
acme.sh --install-cert -d example.top \
--key-file /home/keys/key.pem \
--fullchain-file /home/keys/cert.pem \
--reloadcmd "docker resatrt some-nginx"

正常的话,这里运行着一个nginx容器了,这里的步骤稍微复杂但是细心一点还是没有难度的,特别需要注意的是域名、文件夹和文件名这些内容不要写错。

截止到这里,基本已经完成基本的架构,只需要其他docker容器加入到https这个网段内,通过conf文件,让nginx这个容器可以访问到就可以了。

TIP:这里在使用docker-compos安装前,需要把Nginx的文件夹先创建好,给目录777权限,nginx.conf是文件,conf.d是文件夹

最佳实践

静态博客站简单部署

cd到/home/nginx/conf.d目录,然后编写文件blog.conf文件,然后放到home目录的nginxconf.d文件夹下(记得替换域名)

blog.conf文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# listen on HTTP2/SSL
server {
listen 443 ssl http2;
server_name www.example.com;
# ssl certs from letsencrypt
# ssl on;
ssl_certificate /home/keys/cert.pem;
ssl_certificate_key /home/keys/key.pem;
# dhparam.pem
ssl_dhparam /home/keys/dhparam.pem;

ssl_session_cache shared:SSL:50m;
ssl_session_timeout 30m;
ssl_session_tickets off;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ciphers chosen for forward secrecy and compatibility
# http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html
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';

ssl_prefer_server_ciphers on;

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";

location / {
root /var/www/;
index index.html;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

# redirect HTTP and handle let's encrypt requests
server {
listen 80;
server_name www.example.com;
location / {
return 301 https://$host$request_uri;
}
}

在home目录下的blog放静态资源,然后DNS服务商把www网站解析到服务器即可以访问

安装Jenkins

使用docker-compose方式安装:

创建一个名字叫docker-compose.yml的文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
version: '3'
services:
jenkins:
image: jenkins/jenkins:lts
volumes:
- /home/jenkins/data/:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
ports:
- "8080:8080"
- "50000:5000"
- "10051:10051"
user: root
restart: always
container_name: jenkins
networks:
default:
external:
name: https

创建了一个jenkins的最新版本镜像,并创建运行一个叫jenkins容器端口可以挂载也可以不挂载,因为使用的是域名访问,没有影响。

需要给文件夹赋予权限:

1
chmod 777 /home/jenkins/data

这里我们可以使用ftp工具上传到服务器上的home目录下的jenkins,推荐使用FileZilla Client

然后cd到docker-compose的目录下,使用一下命令安装:

1
docker-compose up -d

安装好之后我们需要得到一串密钥文件,输入命令:

1
docker logs  -f jenkins

可以得到一个密钥,等会安装需要,可以先记录下来,不先安装,先让nginx能代理jenkins容器再来安装。同样的操作的:

jenkins.conf文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
upstream target-server {
server jenkins:8080 fail_timeout=0;
}
# listen on HTTP2/SSL
server {
listen 443 ssl http2;
server_name jenkins.example.top;
# ssl certs from letsencrypt
ssl_certificate /home/keys/cert.pem;
ssl_certificate_key /home/keys/key.pem;
# dhparam.pem
ssl_dhparam /home/keys/dhparam.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect off;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://target-server;
}
}
# redirect HTTP and handle let's encrypt requests
server {
listen 80;
server_name jenkins.example.top;
# send everything else to HTTPS
location / {
return 302 https://jenkins.example.top;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://target-server;
}
}

注意容器是8080端口的,域名改为自己的。target-server这个根据个人修改,每个应用不能重复

接下来就是打开域名,访问Jenkins,把刚才的密钥复制粘贴,安装插件,创建用户

然后需要Jenkins下载下面3个插件:

  • Build With Parameters 输入框式的参数
  • Persistent Parameter 下拉框式的参数
  • Gitee

最后再配置Gitee的用户名密码,能然后的项目部署访问到。

补充:这里后面涉及到项目需要在jengkins使用docker-compos的命令,这里写一下:

1
2
3
4
5
6
进入 Jenkins 容器
docker exec -it jenkins_container_name bash
安装 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
添加执行权限
sudo chmod +x /usr/local/bin/docker-compose

jenkins_container_name是自己jenkins的容器名称。

安装Halo

由于小型的服务器可能承受不住Halo和mysql的压力,这里演示的是H2数据库:

这是官方提供的docker-compose文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
version: "3"

services:
halo:
image: registry.fit2cloud.com/halo/halo:2.17
restart: on-failure:3
volumes:
- ./halo2:/root/.halo2
ports:
- "8090:8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
command:
# 外部访问地址,请根据实际需要修改
- --halo.external-url=http://localhost:8090/

但是我们安装这个文件安装,可能就会报错,版本原因(start_period是有版本限制的),这里我们需要优化调整一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: "3"

services:
halo:
image: registry.fit2cloud.com/halo/halo:2.17.2
restart: on-failure:3
container_name: test #容器名称
networks:
https:
volumes:
- /home/halo2/halo2:/root/.halo2
ports:
- "8090:8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
command:
# 外部访问地址,请根据实际需要修改
- --halo.external-url=https://test.test.top
networks:
default:
external:
name: https

增加了container_name(自定义容器名称,方便接下来的Nginx容器访问),剔除了start_period(主要报错原因,版本问题),增加了networks(加入https网段,和Nginx容器同个网段,可以相互之间通讯访问)

安装好Halo容器,最后就需要使用Nginx来代理这个容器,我们可以编写一个conf文件,存放到home/nginx/conf.d目录下,这样就可以使Nginx容器代理Halo容器了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
upstream halo-server {
server test:8090 fail_timeout=0;
}
# listen on HTTP2/SSL
server {
listen 443 ssl http2;
server_name test.test.top;

# ssl certs from letsencrypt
ssl_certificate /home/keys/cert.pem;
ssl_certificate_key /home/keys/key.pem;
# dhparam.pem
ssl_dhparam /home/keys/dhparam.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect off;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://land-server;
}
}
# redirect HTTP and handle let's encrypt requests
server {
listen 80;
server_name test.test.top;
# send everything else to HTTPS
location / {
return 302 https://test.test.top;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://halo-server;
}
}

需要修改地方:

  • proxy_pass http://halo-server 是 和 halo-server对应的
  • return 302 https://test.test.top 填写自己的域名
  • server_name test.test.top; 填写自己的域名
  • server test:8090 fail_timeout=0; 填写自己容器名称

自动化部署Hexo博客

hexo上传代码需要以下插件:

1
npm install hexo-deployer-git --save

需要改动hexo配置文件:

1
2
3
4
deploy:
type: git
repo: yougitproject
branch: master

上传git代码还需要配置ssh的密钥,同时还需要配置本地的账户名和邮箱

本地生成SSH密钥

1
ssh-keygen

配置git本地的账户名和邮箱

1
2
git config --global user.name "Git用户名" 
git config --global user.email "Git邮箱"

本地编写DockerFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM node:20 as build-stage
LABEL maintainer=LSF
# 创建一个工作目录
WORKDIR /app
COPY . .

# RUN npm install --registry=https://registry.npm.taobao.org
# RUN npm run build

FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app /usr/share/nginx/html

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

giteejenkins联调

  1. 创建一个自由风格的项目;
  2. 然后选择参数化构建过程,有4个参数,分别是写container_name、port、image_name、tag,类型写String;
  3. 源码管理Git填写代码仓库地址。(注意要配置好Gitee的凭据);
  4. 勾选Gitee webhook 触发构建,生成Gitee WebHooks 密码,然后在·仓库的·那里填写这个url和密码,其他可以保持默认;
  5. 最后构建过程选择执行shell。

shell脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/bin/bash
CONTAINER=${container_name}
PORT=${port}

# build docker image
docker build --no-cache -t ${image_name}:${tag} .

checkDocker() {
RUNNING=$(docker inspect --format="{{ .State.Running }}" $CONTAINER 2>/dev/null)
if [ -z $RUNNING ]; then
echo "$CONTAINER does not exist."
return 1
fi

if [ "$RUNNING" == "false" ]; then
matching=$(docker ps -a --filter="name=$CONTAINER" -q | xargs)
if [ -n $matching ]; then
docker rm $matching
fi
return 2
else
echo "$CONTAINER is running."
matchingStarted=$(docker ps --filter="name=$CONTAINER" -q | xargs)
if [ -n $matchingStarted ]; then
docker stop $matchingStarted
docker rm ${container_name}
fi
fi
}

checkDocker

# run docker image
docker run -it d --name $CONTAINER -p $PORT:80 ${image_name}:${tag}

这样基本就搭建完成,本店只要通过hexo g命令上传代码,jenkins就可以自动构建部署了,因为没有使用docker-compose文件所以这里需要shell脚本,后面使用docker-compose就不需要这么复杂的shell脚本

nginx的配置文件与jenkins一样,需要修改域名,target-server和注意容器的端口

自动化部署Vue前端项目

项目根目录本地编写DockerFiledocker-compose文件

DockerFile文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM node:20 as build-stage
LABEL maintainer=Tech

# 创建一个工作目录
WORKDIR /app
COPY . .

RUN npm install --registry=https://registry.npmmirror.com --legacy-peer-deps
RUN npm run build

FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

docker-compose文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: '3'
services:
web:
build:
context: .
dockerfile: Dockerfile
args:
Version: 1.0
image: vueprojrctimg:1.0
container_name: vueprojrct
restart: always
ports:
- 10000:80
networks:
default:
external:
name: https

giteejenkins联调

与自动化部署Hexo博客一样,但是去除掉参数化和改shell脚本:

1
2
docker-compose up -d
docker-compose up --build

nginx的配置文件与jenkins一样,需要修改域名,target-server和注意容器的端口

自动化部署NodeJS项目

本地编写DockerFiledocker-compose文件

项目根目录本地编写DockerFiledocker-compose文件

DockerFile文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM node:20
LABEL maintainer=Tech
# 创建一个工作目录
WORKDIR /app
COPY . .

RUN npm install --registry=https://registry.npmmirror.com --legacy-peer-deps
RUN npm run build

EXPOSE 12006

VOLUME [ "/app/public" ] #不一定挂载出来

CMD [ "node", "dist/bundle.js" ]

docker-compose文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: '3'
services:
web:
build:
context: .
dockerfile: Dockerfile
args:
Version: 1.0
image: nodeprojrctimg:1.0
container_name: nodeprojrct
restart: always
ports:
- 10001:3000
networks:
default:
external:
name: https

giteejenkins联调

与自动化部署Hexo博客一样,但是去除掉参数化和改shell脚本:

1
2
docker-compose up -d
docker-compose up --build

nginx的配置文件与jenkins一样,需要修改域名,target-server和注意容器的端口

可能用到的工具

这里列举了我常用的开发工具和连接服务器工具链接

一些踩过的坑!!

在部署的时候遇到一个巨坑,因为使用的是cloudflare进行·解析,但是有一个断到断的加密过程,看下面图片就知道了,用户访问会被cloudflare先代理,走https,但是cloudflare跟服务器也要走https,不能走http,不然就会出现前端重定向问题!这里一般选择完全的SSL加密

如果是使用cloudflare代理的网站,在安装halo后可能会遇到插件和应用商店看不到的问题,这需要在cloudflare后台缓存->配置->缓存级别改为标准,这也是一个巨坑!

总结

  • 服务器端密钥登录

  • Docker和DockerCompose的安装

  • acme的安装过程

  • Nginx安装和acme的配置

  • 不同的方式安装docker容器项目,实现自动化部署集成并支持https访问