acme.sh证书同步到华为云

项目代码

环境

  • 华为云 ubuntu 18.04
  • Docker version 19.03.8, build afacb8b7f0
  • docker-compose version 1.25.4, build 8d51620
  • image: neilpang/acme.sh v2.8.6
  • image: jenkins/jenkins:lts Jenkins ver. 2.204.5

目标

  • acme.sh自动更新证书
  • 使用华为云的负载均衡 https监听
  • 证书更新后自动同步到华为云

实现方案

  • server上通过docker部署acme.sh
  • 使用nodejs调用华为云api实现更新证书
  • 使用jenkins实现证书更新后自动调用nodejs

部署acme.sh实现自动更新证书

acme.sh可以通过aliyun_dns_api完成证书颁发,需要阿里云的app_key和app_secret。

参考链接

你可以直接安装acme.sh就能实现。但是当你有多个域名并且分布在多个阿里云帐号的时候,直接安装acme.sh可能解决不了问题(尝试过,但是没配置成功),而用docker跑acme.sh可以完美解决这个问题。所以这里用docker来跑acme.sh。

参考 ilaipi/acme.sh-docker 完成部署

自动更新证书到华为云

GitHub Repo 看源码部署

Jenkins自动同步到华为云

acme.sh有notify机制,notify到个人邮箱,jenkins配置一个任务,通过邮件触发(需要安装一个邮件触发的插件Poll Mailbox Trigger Plugin),检查到邮件就执行服务器上的自动更新代码。

(目前还在实验阶段)

在acme的容器内配置邮件发送服务,使用acme支持的mailgun,注册帐号并完成邮件认证。邮件认证的时候可能需要google voice号码(我认证的时候没有看到中国的选项)。最后调用acme.sh --set-notify --notify-hook mailgun来确认是否配置成功,配置成功的话会发邮件到接收邮箱。

在jenkins中配置的是outlook邮箱(host: imap-mail.outlook.com)。

Jenkins Advanced Email Properties

subjectContains=Renew *.xxxxxxx.com success
receivedXMinutesAgo=600 # 意思是10小时内发送的邮件。一般acme是凌晨0点后执行任务

Jenkins Schedule

TZ=Asia/Shanghai
H H(3-7)/3 * * *
# 这样的意思应该是早上3-7点之间执行3次

Docker 常用命令

批量删除容器

docker ps -a | grep Exit | awk '{print $1}' | xargs docker rm

可以修改 grep Exitgrep Created,即根据状态,找到对应的全部id,然后传给docker rm命令,可以修改rm 为其它的命令。

批量删除镜像

docker images | grep '<none>' | awk '{print $3}' | xargs docker rmi -f

构建镜像

# -t 指定镜像名字和Tag
docker build  -t hcp-backend-dev:test .

启动镜像

# 启动镜像hcp-backend-dev:test,指定容器名字为hcp-backend-dev
docker run --name=hcp-backend-dev -dit hcp-backend-dev:test

全部删除docker所有东西

docker system prune --all

删除全部镜像

docker rmi -f $(docker images -a -q)

删除全部容器和挂载盘

docker rm -vf $(docker ps -a -q)

Docker容器迁移

参考链接

通过docker export导出镜像,然后到新服务器import为指定名字的镜像,启动时以新的镜像名来启动。对于volume的迁移,可以直接从源服务器scp传到新服务器。

相关命令:

docker export container_name -o filename.tar
# load image as image_name
docker import filename.tar image_name

Docker 安装优化

修改目录,配置加速

vim /etc/docker/daemon.json

{
"data-root": "/data/docker",
"registry-mirrors": ["https://${TO_BE_REPLACED}.mirror.aliyuncs.com"]
}

data-root 是要存放Docker镜像、容器文件的目录

registry-mirrors,使用阿里的,需要有阿里云帐号,到自己的后台去找地址。在控制台,找到“容器镜像服务 – 镜像中心 – 镜像加速器”,这个页面有个地址。复制即可。

重启docker

systemctl restart docker

Docker Compose Started

安装Docker

参考链接:https://docs.docker.com/install/linux/docker-ce/ubuntu/

安装Docker Compose

Docker Compose可以作为一个Docker Container来运行,安装参考链接:https://docs.docker.com/compose/install/#install-as-a-container

常用命令

# 用户加入到docker组,可以非root用户启动
sudo usermod -a -G docker $USER
# 启动
docker-compose up # 启动,可看日志,但结束后服务停止
docker-compose up -d # 启动,不能看日志,后台运行
# 进入容器
docker-compose exec $service-name bash

Docker Compose Networks

可以在一个docker-compose.yml「A」文件中定义网络,在另外的docker-compose.yml「B」文件中使用网络。

比如,A文件中定义数据库服务:

version: "3.7"

services:
  mysql-blog:
     image: mysql:5.7
     volumes: # 数据卷,映射本地文件夹
       - /data/mysql/blog:/var/lib/mysql
     ports: # 如果不写端口映射的话,外部无法连接该mysql(下方WordPress连接没问题)
       - "13306:3306" # 13306 是外部使用,不同的compose文件中使用时,请使用mysql的端口3306,即container中的端口
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: "Xeroxes6136;cobras"
       MYSQL_DATABASE: blog
       MYSQL_USER: blog
       MYSQL_PASSWORD: blog
     networks:
       mysql-blog:
         aliases:
           - mysql-blog # 给mysql-blog网络起别名,其它服务可通过别名引用
           - mysql-blog2 # 可以有多个别名
networks:
  mongo-blog:
    name: mongo-blog

在B中引用A中的mongo-blog网络:

version: "3.7"
 services:
   blog:
     image: wordpress:latest
     volumes:
       - /data/wordpress/blog:/var/www/html
     ports:
       - "63380:80"
     restart: always
     privileged: true
     environment:
       WORDPRESS_DB_HOST: mysql-blog:3306 # 这里使用网络名字即可连接
       WORDPRESS_DB_NAME: your-db-name
       WORDPRESS_DB_USER: your-db-user
       WORDPRESS_DB_PASSWORD: your-db-password
       # 定义域名
       WORDPRESS_CONFIG_EXTRA: "define('WP_HOME','your-blog-domain'); define('WP_SITEURL','your-blog-domain');"
     networks:
       - mysql-blog
networks:
   mysql-blog:
     external: # 表示使用外部的网络
       name: mysql-blog

在其它container自己的代码中,也可以使用mysql-blog:3306这样的字符串去连数据库。