前言

(入职后几天内写的)

这两天在处理入职和开发环境的搭建,第一天被各种需要填写的表单给占用了,下午才有时间从开发主管那里接受代码。

公司使用的是 bitbucket.org,功能与 Gitlab 基本相似,但又属于三方服务搭建的,所以又比较类似 Gitee,不过应该都是私有库。注册需要使用到公司分配的个人邮箱,会有很多开发组的消息,通过邮箱来通知到个人。注册成功后会被拉进开发组,可以访问到所有的项目和库。

之后就是搭建开发环境了。公司使用的是自研的框架,如 learnkuLaravel 入门教程,为确保整体的开发环境和生产环境的一致性,需要使用相同版本的应用服务。公司使用了 docker,容器化部署需要的服务,如 nginxphpmysqlredisbeanstalkd(消息队列)等。

开发主管给了一个 Mac通过Vagrant + VirtualBox 安装Docker 教程,让搭建环境:mac vagrantvirtrualbox 安装 ubuntu 22.04 / 24.04。之后给了主项目代码库和文档库的地址,可以设置 SSH keys 来直接 clone 项目。Bitbucket 的添加 SSH key 的弹出框里给出了获取本地公钥的方法:

cat ~/.ssh/id_rsa.pub | pbcopy

如果粘贴出来为空,就需要百度去生成公钥和私钥了。这个对于开发来说,还是挺重要的。

此时就可以根据文档库对应的部署文档去一步步实现环境搭建了。

过程

按照填坑和搭建的顺序,做如下的经验总结。

1. 安装 ubuntu 22.4 虚拟机

一开始说是可以 Mac 本机安装,因为有安装 Docker Desktop 版本。虚拟机需要 Vagrant + VirtualBox,之前搞过几次,但要么版本不兼容,要么装好了也没怎么用。如果桌面版可以用,那就不想麻烦按照教程去搞虚拟机了。

本地 iterms 按照教程执行。先是遇到 docker: Get https://registry-1.docker.io/v2/: net/http: request canceled  报错,换镜像源就是了。在设置 -> Docker Engine 中修改 registry-mirrors 项:

Docker/DockerHub 国内镜像源/加速列表(7月7日更新-长期维护)

选择免费、免登录的轩辕镜像源:

  "registry-mirrors": [
    "https://docker.xuanyuan.me"
  ]

nginx 安装 ok,但到了其他的应用都是自定义的版本,需要登录之后操作 docker login docker.xx.xx,这也是我之前没有遇到过的。然后安装的第一项 mariadb 就报错了:

Docker Image Format v1 and Docker Image manifest version 2, schema 1 support has been removed. Suggest the author of docker.xx.xx/xx/mariadb:v10.1.10-xx to upgrade the image to the OCI Format or Docker Image manifest v2, schema 2. More information at https://docs.docker.com/go/deprecated-image-specs/

百度了一下,找到一篇 Image manifest version 2, schema 1,提到 schema 1 已经废弃了。要么升级到 manifest version 2, schema 2 要么使用 FROM dockerfile 更新。后者没试过,前者没办法搞,因为是公司内部管理的 docker 镜像库,也不能自己改动。使用 deepseek 归纳解决兼容 v1 的方法,尝试过 skopeo 和 crane 工具,代替 docker 去下载镜像,但都被拒绝了。

docker manifest inspect --insecure docker.xx.xx/xx/redis:v2.8.17-xx 可以看到报错信息 unsupported manifest media type and no default available: application/vnd.docker.distribution.manifest.v1+prettyjw,也即是 v1 版本。--insecure 并不能越过版本检测而下载镜像。

公司的镜像库显然太陈旧,也太久没人维护了。

当然还有釜底抽薪的方法,那就是降低 docker 的版本,到它可以支持下载 v1 的那一版。但让我放弃当前的最新版本去做适配开发环境,想想还是算了,搞虚拟机吧。

vagrant 和 virturalbox 实现虚拟机安装

按照上面提供的 Mac通过Vagrant + VirtualBox 安装Docker 教程,先后下载安装 vagrant 和 virtualBox:

安装 vagrant

下载安装 VirtualBox

vagrant 是配置脚本,可以调整虚拟机的配置,如占用资源,共享文件目录,端口映射等;virturalbox 则是承载虚拟机的工具,与 Mac 下的 Fusion 差不多。

命令行查看版本:

> vagrant --version
Vagrant 2.4.7
> vboxmanage --version
VirtualBox 7.1.10r169112

教程中虽然是 vagrant init centos/7centos 作为案例初始化的,但也提供了 ubuntu 版本的 vagrantfile 的下载地址:

ubuntu box 列表

百度了一下,ubuntu 22.04 LTS 对应发布名称为 Jammy24.04 LTS 对应 Noble。这里选择安装 Jammy 版本,页面有安装步骤和指令:

# Option 1: Create a Vagrantfile and initiate the box
vagrant init ubuntu/jammy64 --box-version 20241002.0.0
# Option 2: Open the Vagrantfile and replace the contents with the following
# 初始化后创建的 Vagrantfile 默认设置了两个配置项,再加上端口和共享文件夹配置(代码目录)
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"
  config.vm.box_version = "20241002.0.0"
  # 虚拟机映射到本地的端口
  config.vm.network "forwarded_port", guest: 80, host: 80
  config.vm.network "forwarded_port", guest: 81, host: 81
  config.vm.network "forwarded_port", guest: 3306, host: 3306
  config.vm.network "private_network", ip: "192.168.33.10"
  # 虚拟机共享文件夹
  config.vm.synced_folder "/Users/mac/Code/xx", "/var/lib/xx", create:true, type:"nfs", nfs_udp: false, nfs_version: 3
end
# Bring up your virtual machine
# 启动虚拟机,需要在 Vagrantfile 同目录下
vagrant up

默认安装好的 ubuntu box 是 2 核 内存 2 G,如果想要修改可以参考 vagrant 文档:Vagrant VirturalBox Configuration

# 设置分配的内存和 CPU
config.vm.provider "virtualbox" do |v|
  v.memory = 1024
  v.cpus = 2
end

需要放在 xx 范围内:

Vagrant.configure("2") do |config|
...
end

放完之后发现,原来注释也有一端关于 内存和 CPU 配置的示例。

并且,百度回顾了一下 vagrant 的一些基本指令:

# vagrant 修改配置(Vagrantfile)后使其生效
vagrant reload --provision
# 初始化虚拟机并生成 Vagrantfile 配置文件
vagrant init ubuntu/jammy64 --box-version 20241002.0.0
# 启动虚拟机
vagrant up
# 关闭虚拟机
vagrant halt
# 进入虚拟机
vagrant ssh
# 默认的 shell 账号密码
vagrant/vagrant
# 宿主机上传文件
vagrant upload vagrant upload source [destination] [name|id]
vagrant upload docker-compose.yaml /home/vagrant/ docker-compose.yaml

教程中还有设置启动后自动安装 docker-ce 的,但配置后启动报错,所以放弃了,先进入 ubuntu 再去安装。

2. ubuntu 22.04 安装 docker

ubuntu 的安装指令为 apt-get,与 centos 中的 yum、Mac 下的 brew 功能相似。

ubuntu 安装 docker engine 官方文档

当然,这边主要参考公司给的文档

#ubuntu操作系统
$ sudo apt-get update
$ sudo apt-get -y install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update
#查看可用版本
$ apt-cache madison docker-ce
docker-ce | 5:28.3.1-1~ubuntu.22.04~jammy | https://download.docker.com/linux/ubuntu jammy/stable amd64 Packages
 ...
 docker-ce | 5:20.10.13~3-0~ubuntu-jammy | https://download.docker.com/linux/ubuntu jammy/stable amd64 Packages
#安装
$ sudo mkdir /etc/docker/
$ sudo touch /etc/docker/daemon.json
$ cat /etc/docker/daemon.json
{
  "bip": "172.17.42.1/24",
  "dns": [
    "172.17.42.1",
    "114.114.114.114"
  ],
  "registry-mirrors": [
    "https://reg-mirror.qiniu.com",
    "https://hub-mirror.c.163.com",
    "https://registry.aliyuncs.com"
  ]
}
$ sudo apt-get -y install docker-ce=5:20.10.13~3-0~ubuntu-jammy

这里选择最低的版本,5:20.10.13~3-0~ubuntu-jammy

后续如果下载镜像失败或者缓慢,还可以修改 /etc/docker/daemon.json 文件中的 registry-mirrors 数组,替换镜像源使之生效:

# 配置重新加载
sudo /bin/systemctl daemon-reload
# 重新启动
sudo systemctl restart docker

如果安装过程中出现异常,可以先删除 docker 再重新安装:

sudo apt-get remove docker
# 删除其他无用依赖项
sudo apt autoremove

如果想要下载特定的版本,不确保兼容性、可用性,可以到 docker 下载 ubuntu 版本列表 下载选择需要的版本,这种方式在上面的官方文档里也有说明。

# 下载包
wget https://download.docker.com/linux/ubuntu/dists/xenial/pool/stable/amd64/docker-ce_1.13.1~ce-0~ubuntu-xenial_amd64.deb
# 安装包
sudo dpkg -i docker-ce_1.13.1~ce-0~ubuntu-xenial_amd64.deb

添加 xx 用户并加入 docker 组

这是项目默认的部署用户,会将部署文件放在 xx 的根目录下,即 /home/xx/

加入 docker 组可以使得登录 xx 账号后 docker 相关指令不需要提权 sudo 就可以执行。
# 创建 xx 用户
# 也可以使用 sudo adduser xx 交互式指令,密码会提示输入
vagrant@ubuntu2204:~$ sudo useradd -m -s /bin/bash xx
vagrant@ubuntu2204:~$ sudo passwd xx
# 为用户分配权限(添加用户组)
# 加入 sudo 表是可以提权执行管理员操作
vagrant@ubuntu2204:~$ sudo usermod -a -G docker xx
vagrant@ubuntu2204:~$ sudo usermod -aG sudo xx
# 删除用户(谨慎使用)
vagrant@ubuntu2204:~$ sudo userdel -r xx
# 设置免密登录(可选)
# 修改 /etc/sudoers 文件
vagrant@ubuntu2204:~$ sudo chmod u+w /etc/sudoers
# xx
xx ALL=(ALL) NOPASSWD:ALL
vagrant@ubuntu2204:~$ sudo chmod u-w /etc/sudoers
# 立即生效组权限
newgrp docker
# 如果上面的报错,可以重新登录后切换用户账号
vagrant@ubuntu2204:~$ su -l xx
# 验证权限
xx@ubuntu2204:~$ docker ps

sudoers 文件说明

如果出现 dial unix /var/run/docker.sock: connect: permission denied报错,就添加用户到 docker 组,再切换到用户下执行。

docker 下载安装镜像并启动容器服务

需要下载的 docker 镜像有 nginx xx redis beanstalkd mariadb,公司文档有提供具体版本安装指令。

docker pull nginx:1.22-alpine
# docker login docker.xx.xx
docker pull docker.xx.xx/xx/mariadb:v10.1.10-xx
docker pull docker.xx.xx/xx/beanstalkd:v1.10.0-xx
docker pull docker.xx.xx/xx/redis:v2.8.17-xx
docker pull docker.xx.xx/xx/xx:v1.1.1-xx

除了 nginx,其他的都属于公司自定义的镜像,需要验证登录权限。

执行 nginx 就已经卡住了,太慢了,更换镜像也不太好使。开发主管提了可以从他那边复制 tar 镜像再运行:

# 远程下载
scp xx@192.168.1.2:~/Desktop/vagrant/nginx.tar ./
# docker 运行镜像
docker load -i nginx.tar

其他的属于从公司的 docker 服务器上下载镜像文件,没有出现问题。

docker 运行容器指令可以在安装教程,或者 docker-run.md 中找到,可以一个一个的启动服务。

docker run \
--name nginx \
-d \
-v /home/xx/nginx/nginx.conf:/etc/nginx/nginx.conf \
-v /home/xx/nginx/fastcgi_params:/etc/nginx/fastcgi_params \
-v /home/xx/nginx/sites-enabled:/etc/nginx/sites-enabled \
-v /home/xx/nginx/sites-available:/etc/nginx/sites-available \
-v /home/xx/nginx/conf.d:/etc/nginx/conf.d \
-v /var/log/nginx:/var/log/nginx \
-v /var/lib/xx:/var/lib/xx:rw \
-v /data/xxx:/data/xxx:rw \
-v /var/www:/var/www \
-v /var/run:/var/run \
-p 80:80/tcp \
--restart=always \
--privileged \
nginx:1.22

不想这么一个个的启动,有一个 docker-compose 指令,可以按照 docker-compose.yml 配置按组运行 docker 服务。询问确有这个 docker-compose.yml 文件,通过 vagrant upload 指令上传到 vagrant 目录下,再将其 mv 到 /home/xx 下。

下载安装 docker-compose(非必要):

# 安装依赖包
sudo apt-get install -y curl jq
# 下载并重命名
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 修改为可执行文件
sudo chmod +x /usr/local/bin/docker-compose
# 查看版本
docker-compose version
# 强制卸载挂载点
fuser /usr/local/bin/docker-compose
后来了解了 docker-compose 与 docker compose 的区别,才知道,原来安装 docker-ce 默认会安装好 docker compose 的插件,不带连接字符,可以直接调用 docker compose up -d 指令。如果确定没有安装 compose 插件,才需要单独安装这个 docker-compose 工具。

此时启动(docker-compose up)可能会有问题,开发主管告知需要对 nginxmariadbredis 等配置复制到 \home\xx 目录下。

登录到上面的测试站,将 nginxmariadbredis 目录压缩成 tar.gz 包,再远程下载到本地解压。

# 测试站 /home/xx 目录
tar -zcvf nginx.tar.gz nginx
tar -zcvf redis.tar.gz redis
tar -zcvf mariadb.tar.gz mariadb
# 本地 ubuntu /home/xx 目录
sudo scp xx@xx:~/nginx.tar.gz ./
sudo tar -zxvf nginx.tar.gz
sudo scp xx@xx:~/redis.tar.gz ./
tar -zxvf redis.tar.gz
sudo scp xx@xx:~/mariadb.tar.gz ./
tar -zxvf mariadb.tar.gz

之后需要先按照 xx 手动部署流程.md 中的 mariadb 部分,先临时启动一个 mariadb 容器,初始化数据库,一直到创建数据库。不然,直接 docker-compose up 启动,mariadb 数据库会一直处于 restarting 的状态中。

docker-compose up 启动需要确保没有相同名称的容器,比如前面临时创建的 mariadb 容器,需要先删除这个容器,再启动。

docker ps
# 删除容器,根据上面的容器列表,获取容器id
docker rm mariadb
docker-compose up

然后还有三小步,分别修改 nginx、mariadb、xx,然后就可以浏览器访问系统了。

  • 切换 nginx 站点配置,切换到默认的 xx 站点

测试站复制来的 nginx 配置文件中,默认启用的是 xx 站点,配置默认读取的是 .conf 文件,所以:

cd nginx/sites-enabled/
mv xx.conf xx
mv yy yy.conf
  • 创建 xx_yy 数据库

如果在上面临时启动 mariadb 容器过程中没有执行最后一步,宿主机安装 mysql,创建xx_{{lab_id}}数据库,则这里需要登录到 mariadb 中创建数据库。

# 进入 mariadb 容器
docker exec -it mariadb /bin/bash
# 免密登录 xx
mysql -uxx
create database xx_yy;
  • 在 xx 容器中 执行初始化脚本
docker exec -it xx bash
cd /var/lib/xx/
# 创建 ORM 表,注意 cli/xx 是没有空格的
SITE_ID=cf LAB_ID=xx php cli/create_orm_tables.php
# 创建登录用户
SITE_ID=cf LAB_ID=xx php cli/add_user.php xx

需要注意的是,这里 创建 ORM 表的脚本是有日志输出的,而且还很多,高亮显示的如果没有日志输出,则说明脚本并没有执行成功。 需要考虑环境中的 php 是否为 php 7.0,项目的 vendor 目录也要在 php 7.0 下生成。否则需要删除目录,切换到 php 7.0 版本之后再 comppse install

需要注意的是,最新的分支为 3.30,本地环境切换分支之后,第一次的需要初始化,之后更新 vendor 或者 modules 目录都需要执行子模块同步与更新指令。

git submodule init
git submodule sync && git submodule update && git pull
git checkout 3.30
xx ~ $ composer self-update
xx ~ $ composer install
git submodule sync && git submodule update && git pull

最后,就可以浏览器访问项目了。

http://192.168.33.10/xx

坑点总结

最终的版本:

Vagrant 2.4.7
VirtualBox 7.1.10r169112
Docker 20.10.13
  • docker image 的镜像源私库的需要登录,公共库的需要设置 image 镜像源,不然会一直报错,或者速度慢的可怕,然后再失败
  • (之后发现的)docker 镜像太陈旧,只支持 AMD 版本,不支持 arm64等架构,且 docker-ce 版本不能超过 5:24.0.9-1~ubuntu.22.04-jammy
  • docker compose 启动并不是一步到位的,需要先去初始化 mariadb 容器,设置数据库,账号等,不然数据库会一直 restarting
  • (之后发现的)vagrant - ubuntu 虚拟机 - docker 容器这一套三连,会导致共享文件夹挂载不稳定,经常卡掉挂载状态,相关代码目录虚拟机和容器都无法访问,谁访问谁卡死