使用 Docker 来构建 Typecho 服务吧 ~

(此处省略300字前言…)

按如下结构建立文件夹:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
├── mysql
│      └── conf.d                  // mysql配置文件目录
│      └── data                    // mysql数据目录
├── nginx
│      └── conf.d                  // nginx配置目录
│      └── ssl                     // ssl证书目录
│      └── logs                    // nginx日志文件目录
├── php-fpm
│      └── Dockerfile              // php构建文件
│      └── typecho                 // typecho路径
│             └── blog                 // typecho站点,请解压typecho程序到此文件夹
├── docker-compose.yml

docker-compose.yml

先看看整体结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
version: "2"
networks:
  default:
    external: false
    name: app-tier
services:
  mysql:
    image: mysql:8.0
  php-fpm:
    build: ./php-fpm
  nginx:
    image: nginx:1.23.3-alpine

由上到下,三个部分:

  • version 指定此配置的版本,一般与 docker-compose 版本对应
  • networks 定义网络,如果多个容器都在同一个网络下,那么它们之间可以通过容器名互相访问,即 服务名:端口 代替 IP:端口 。这里定义了一个名为 app-tier 的默认网络
  • services 部分是定义服务,这里定义了 mysqlphp-fpmnginx 三个服务,下面分而述之。

mysql

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
mysql:
  image: mysql:8.0
  container_name: mysql
  restart: always
  environment:
    TZ: Asia/Shanghai
    MYSQL_ROOT_PASSWORD: 12345678
  ports:
    - 4417:3306
  volumes:
    - ./mysql/data:/var/lib/mysql
    - ./mysql/conf.d:/etc/mysql/conf.d
    - ./mysql/init:/docker-entrypoint-initdb.d/
  command:
    - --character-set-server=utf8mb4
    - --collation-server=utf8mb4_unicode_ci
  networks:
    - default

这里的 mysql 是服务名,也是容器名

  • image 是指定使用的镜像,通常格式:镜像名:版本号;可以在 Docker Hub 上找到我们需要的镜像,这里我们使用的是 mysql:8.0,也就是使用的是 mysql8.0 版本。

  • container_name 是指定容器名,后续操作都是基于容器名的,这里指定为 mysql

  • restart 是指定容器重启策略,这里指定为 always,也就是容器异常退出后,自动重启

  • environment 是指定环境变量,这里指定的 TZ 是时区,MYSQL_ROOT_PASSWORDroot 用户的密码,更多环境变量可以参考 官方文档

  • ports 是指定端口映射,前面是宿主机端口,后面是容器端口,也就是将宿主机的 4417 端口映射到容器的 3306 端口,这样我们就可以通过 localhost:4417 来访问 mysql

  • volumes 是指定挂载目录,前面是宿主机目录,后面是容器目录,挂载之后,二者互通,修改任意一方的文件,另一方都会同步修改,这里我们挂载了三个目录,分别是

    • ./mysql/data:/var/lib/mysql 数据持久化
    • ./mysql/conf.d:/etc/mysql/conf.d 配置文件,在里面添加的 .cnf 文件,文件内容将被合并到mysql的配置文件中
    • ./mysql/init:/docker-entrypoint-initdb.d/ 初始化目录,可以在里面添加 .sql 文件,如创建用户、数据库等,里面的所有sql都将在容器初始化时自动执行
  • command 是指定启动命令

  • networks 是指定网络,这里指定为 default,即上文定义的默认网络 app-tier

php-fpm

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
php-fpm:
    build: ./php-fpm
    container_name: php-fpm
    restart: always
    environment:
      TZ: Asia/Shanghai
    volumes:
      - ./php-fpm/typecho/blog:/var/www/blog
    networks:
      - default
    depends_on:
      - mysql
1
2
3
4
5
6
7
8
FROM php:8.1.13-fpm-alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk update \
&& apk add alpine-conf \
&& /sbin/setup-timezone -z Asia/Shanghai \
&& apk del alpine-conf \
&& docker-php-ext-install pdo pdo_mysql calendar \
&& printf '[PHP]\ndate.timezone = Asia/Shanghai\n' > /usr/local/etc/php/conf.d/tzone.ini

这里的 php-fpm 是服务名,也是容器名

  • build 是指定构建镜像,这里指定的是 ./php-fpm 目录,也即从通过路径下的 Dockerfile 文件构建,看下 Dockerfile 文件:

    • FROM 指定以哪个镜像为基础进行构建。这里我们使用的是 php:8.1.13-fpm-alpine 镜像
    • RUN 表示执行命令。由于Docker每执行一次 RUN 就会多构建一层 所以使用 & 将多条命令拼接在一次执行,从上往下命令大意:
      • 设置alpine apk 仓库为 aliyun 镜像仓库
      • 更新软件
      • 安装 alpine-conf (alpine 不包含时区文件,故需下载)
      • 设置系统时区为 Asia/Shanghai
      • 删除 alpine-conf (释放空间)
      • 安装 pdopdo_mysqlcalendar 等PHP扩展
      • 设置 PHP 时区为 Asia/Shanghai
  • volumes 挂载了两个目录,对应两个 typecho 站点,需要将 typecho 程序放到这两个目录下

  • depends_on 是指定依赖,也就是说 php-fpm 服务启动之前,必须保证 mysql 服务已经启动

nginx

上配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
nginx:
  image: nginx:1.23.3-alpine
  container_name: nginx
  restart: always
  ports:
    - 80:80
    - 443:443
  volumes:
    - ./nginx/conf.d:/etc/nginx/conf.d
    - ./nginx/logs:/var/log/nginx
    - ./nginx/ssl:/etc/nginx/ssl
    - ./php-fpm/typecho/blog:/var/www/blog
  networks:
    - default
  depends_on:
    - php-fpm
  environment:
    TZ: Asia/Shanghai

到这里就没什么好说的了,端口映射、挂载目录等等和前面一样。接下来看向 ./nginx/conf.d ,在其中新建一个 .cnf 文件作为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
server {
    listen 80;
    server_name localhost:80
    index index.php index.html index.htm default.php default.htm default.html;
    root /var/www/blog;

    #伪静态
    if (!-e $request_filename) {
        rewrite ^(.*)$ /index.php$1 last;
    }

    #PHP
    location ~ [^/]\.php(/|$) {
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED /var/www/blog$fastcgi_path_info;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_param SCRIPT_FILENAME /var/www/blog$fastcgi_script_name;
        include fastcgi_params;
    }

    #禁止访问的文件或目录
    location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md) {
        return 404;
    }
}

关于nginx配置就不多展开了,其中,listen 指定了站点端口,root 指定了站点目录,和我们在 nginx 中挂载路径一致,然后就是伪静态、反向代理和访问限制。这里反向代理中使用了:fastcgi_pass php-fpm:9000 即通过服务名来和 fpm 容器连接,这背后的 DNS 等工作将由 docker 自动完成。

到这里,docker-compose.yml就写完了, 最后整合以下,完整版如下:

 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
54
version: "2"
networks:
  default:
    external: false
    name: app-tier
services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    restart: always
    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: 12345678
    ports:
      - 4417:3306
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/logs:/var/log/mysql
      - ./mysql/conf.d:/etc/mysql/conf.d
      - ./mysql/init:/docker-entrypoint-initdb.d/
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    networks:
      - default
  php-fpm:
    build: ./php-fpm
    container_name: php-fpm
    restart: always
    environment:
      TZ: Asia/Shanghai
    volumes:
      - ./php-fpm/typecho/blog:/var/www/blog
    networks:
      - default
    depends_on:
      - mysql
  nginx:
    image: nginx:1.23.3-alpine
    container_name: nginx
    restart: always
    ports:
      - 80:80
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/logs:/var/log/nginx
      - ./nginx/ssl:/etc/nginx/ssl
      - ./php-fpm/typecho/blog:/var/www/blog
    networks:
      - default
    depends_on:
      - php-fpm
    environment:
      TZ: Asia/Shanghai

启动

最后,在我们的文件夹下打开终端,键入以下命令,也即启动服务并在后台运行:

1
docker compose up -d

等待拉取镜像和构建可能需要一些时间,当这一切完成后,浏览器访问 localhost:80 就会进入typecho 安装页啦~