前言

作为程序员,一直以来的开发环境都是在虚拟机下。既可以标准化、又方便迁移,还有一点是不会弄脏弄乱原生系统。特别是用 Laravel 框架的时候,Homestead + Vagrant + VirtualBox 非常好用,一个 vagrant up 命令把所有依赖都装好,开箱即用。让我们把时间和精力都放在开发上。

不过用的时间长了,Homestead 也是有一定的弊端的。比如启动时间长、吃硬盘、耗资源,当时就想着能不能用 Docker 替代虚拟机。早期的时候 Laravel 官方还没有基于 Docker 的解决方案,不过有一些第三方的,怕不靠谱就懒得折腾了。而且 Homestead 本身确实比较优秀,用起来还是比较方便的,就一直拖下来了。现在官方出了 Sail,正好把之前几个项目都转到 Sail 环境下,把我的 MBP 的资源都释放出来。

网上很多类似迁移教程都是针对新项目的。本篇文章记录的是老项目从 Homestead 迁移到 Sail。老项目比新项目要复杂一些,如果你正好有这方面需求,希望这篇文章能够帮助到你。

我在迁移不同的项目过程中都会踩到不同的坑,解决方案我会补充在文章里。如果你碰到了问题,仔细看看文章里面有没有解决方案。如果没有,欢迎给我留言。

1. 安装 Docker

这个就不说了,很简单,网上教程一大堆。

2. 关闭 .env 里面的 redis 和 memcached 配置

FILESYSTEM_DRIVER=public
BROADCAST_DRIVER=log
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=memcached
SESSION_LIFETIME=120

改为:

FILESYSTEM_DRIVER=public
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

不关闭 redis 配置的话,后面执行 composer 命令的时候会因为没有 redis 服务而报错。

3. 安装 Sail

$ cd ./project
$ docker run --rm \
    -u "$(id -u):$(id -g)" \
    -v $(pwd):/var/www/html \
    -w /var/www/html \
    laravelsail/php81-composer:latest \
    composer require laravel/sail --dev

离开了 Homestead 环境,我们假设原生系统下没有安装 php 和 composer「至少我的是这样」。所以要通过 composer 去安装 Sail 就成了难题了。难不成为了装 Sail 再装一套 php + composer?那就与 Docker 精神背道而驰了。细心的 Laravel 团队肯定也想到了这一点,所以提供了一个只有 php + composer 的小容器 laravelsail/phpXX-composer 给我们来安装 Sail。

这个 phpXX 是该项目下对应的 php 版本,比如 74、80、81。例子里我们就用 81 来演示。

当然,你可以在以前的 Homestead 环境下执行 composer require laravel/sail --dev,完全没有问题,效果是一样的。

如果在执行命令的时候有什么组件因为 php 扩展的问题报错,可以先在 composer.json 里把报错的组件删掉,等 Sail 搭好了再重新安装。因为毕竟这是一个简化版的镜像,不会象 Sail 开发环境那样启用很多扩展,它的目的只是安装 Sail。

4. 生成 docker-compose.yml

$ docker run --rm \
    -u "$(id -u):$(id -g)" \
    -v $(pwd):/var/www/html \
    -w /var/www/html \
    laravelsail/php81-composer:latest \
    php artisan sail:install --with=mysql,redis,memcached

上一步已经把 Sail 安装好了,现在就是要生成 docker-compose.yml 编排文件。--with 后面跟的是这个项目下面需要的组件。支持的有:

  • mysql
  • pgsql
  • mariadb
  • redis
  • memcached
  • meilisearch
  • minio
  • selenium
  • mailhog

点击参阅官方说明

只要把需要的组件加在 with 后面,就会自动编排到配置文件里面。演示中我添加了 mysqlredismemcached

如果用到了 VSCodeRemote - Containers 来管理开发环境,可以在 --with=XXX 后面加上 --devcontainer,这样还会额外生成 VSCode 需要的 devcontainer.json 文件。

完成这步操作以后就可以恢复 .env 里的 redis 和 memcached 了。

其实到这一步 Sail 就算安装好了,可以运行 ./vendor/bin/sail up。后面的操作是一些优化步骤。

5. 修改 Dockerfile

$ cp -r ./vendor/laravel/sail/runtimes ./docker

因为一些众所周知的原因,我们需要对 Dockerfile 进行一些修改和优化,而 Dockerfile 文件原本在 ./vendor/laravel/sail/runtimes/X.X 下面「又是 XX」。Laravel 的约定是不能直接修改 ./vendor/ 下的任何文件,因为一更新就没啦,所以我们需要把它复制出来。

./vendor/laravel/sail/runtimes 整个文件夹复制一份放在项目根目录下,文件夹名字改为 dockerdocker 下面有 7.48.08.1 三个子文件夹,里面的文件都一样,用哪个版本的 php 就修改相应文件夹下面的文件。咱们还是用 8.1 来演示。

Dockerfile 用来创建一个容器
docker-compose.yml 用来创建一堆容器,并且按照一定的网络和依赖关系组合起来
$ vim ./docker/8.1/Dockerfile
FROM ubuntu:22.04

LABEL maintainer="Taylor Otwell"

ARG WWWGROUP
ARG NODE_VERSION=16
ARG POSTGRES_VERSION=14

WORKDIR /var/www/html

ENV DEBIAN_FRONTEND noninteractive
ENV TZ=UTC

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN apt-get update \
.
.
.

改为:

FROM ubuntu:20.04

LABEL maintainer="Taylor Otwell"

ARG WWWGROUP
ARG NODE_VERSION=16
ARG POSTGRES_VERSION=14

WORKDIR /var/www/html

ENV DEBIAN_FRONTEND noninteractive
ENV TZ=Asia/Shanghai

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

ADD sources.list /etc/apt/

RUN apt-get update \
.
.
.
  • FROM ubuntu:22.04 => FROM ubuntu:20.04 我比较习惯 20.04,这个改不改随个人喜好。改成 20.04 以后,该文件中的 jammy 全部要改成 focal
  • ENV TZ=UTC => ENV TZ=Asia/Shanghai 我是中国人🇨🇳
  • ADD sources.list /etc/apt/ 给容器启动的时候添加国内镜像源

6. 设置镜像源

$ vim ./docker/8.1/sources.list
# 默认注释了源码仓库,如有需要可自行取消注释
deb http://mirrors.ustc.edu.cn/ubuntu/ focal main restricted universe multiverse
# deb-src http://mirrors.ustc.edu.cn/ubuntu/ focal main restricted universe multiverse

deb http://mirrors.ustc.edu.cn/ubuntu/ focal-security main restricted universe multiverse
# deb-src http://mirrors.ustc.edu.cn/ubuntu/ focal-security main restricted universe multiverse

deb http://mirrors.ustc.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
# deb-src http://mirrors.ustc.edu.cn/ubuntu/ focal-updates main restricted universe multiverse

deb http://mirrors.ustc.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
# deb-src http://mirrors.ustc.edu.cn/ubuntu/ focal-backports main restricted universe multiverse

# 预发布软件源,不建议启用
# deb http://mirrors.ustc.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse
# deb-src http://mirrors.ustc.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse

几点说明:

  • 这里我用了中科大的源,用什么源也是个人喜好,只不过我一开始用阿里云的源的时候一直超时,换中科大的就没问题。
  • 不管什么源,只能用 http,不能用 https,会报下面的错误:

    Certificate verification failed: The certificate is NOT trusted. The certificate issuer is unknown.  Could not handshake: Error in the certificate verification.
  • 重复一遍,20.04focal22.04jammy

7. 修改 docker-compose.yml

$ vim ./docker-compose.yml
# For more information: https://laravel.com/docs/sail
version: '3'
services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.1
.
.
.

改为:

# For more information: https://laravel.com/docs/sail
version: '3'
services:
    laravel.test:
        build:
            context: ./docker/8.1
.
.
.

前面选了 8.1,这里就写 8.1

8. 启航!

$ ./vendor/bin/sail up

后记

第一次 sail up 生成镜像的时候还是挺耗时的,需要耐心等待一段时间。这个时候网络环境特别重要,这就是为什么要那么费劲添加国内镜像源了。

如果卡在下面这个地方一直不动:

#0 192.1 gpg: keybox '/root/.gnupg/pubring.kbx' created

解决步骤:

  1. 打开第 5 步里的 Dockerfile
  2. 找到 hkp://keyserver.ubuntu.com:80
  3. 改为 hkp://keyserver.ubuntu.com