从Docker-Desktop迁移到wsl2

最近更新升级了最新版本的 Docker Desktop 4.20.0 ,然后发现了一个 bug #13524,然后降级一个版本之后又发现了另一个 bug #13477。决定寻找替代品,尝试了 Podman Desktop 之后放弃了,最终决定直接使用 wsl2。记录一下迁移以及踩坑过程。 WSL 遇到的无法解决的问题 microsoft/WSL#5118 导致无法使用 pnpm,只能使用 yarn、npm 替代。 修改源 使用中科大的软件源 https://mirrors.ustc.edu.cn/ # 备份源文件 $ sudo mv /etc/apt/sources.list /etc/apt/sources.list.backup # 切换 root 用户 $ sudo su # 写入中科大的源 $ echo "deb https://mirrors.ustc.edu.cn/ubuntu/ jammy main restricted universe multiverse deb-src https://mirrors.ustc.edu.cn/ubuntu/ jammy main restricted universe multiverse deb https://mirrors.ustc.edu.cn/ubuntu/ jammy-security main restricted universe multiverse deb-src https://mirrors.ustc.edu.cn/ubuntu/ jammy-security main restricted universe multiverse deb https://mirrors....

2023-06-02 · 3 分钟

Xdebug使用Dbgp协议与PHPStorm通信过程

向 IDE 发起连接请求 <?xml version="1.0" encoding="ISO-8859-1"?> <init appid="1" idekey="PHPSTORM" language="PHP" protocol_version="1.0" fileuri="" xmlns="urn:debugger_protocol_v1"> <engine version="1.0.0"> <![CDATA[SDB]]> </engine> <author> <![CDATA[Chance]]> </author> </init> feature_set -i 1 -n show_hidden -v 1 feature_set:命令名称,用于设置调试器的功能。 -i 1:命令的唯一标识符,用于在调试器和 IDE 之间进行通信。 -n show_hidden:要设置的功能名称,即显示隐藏变量。 -v 1:功能的值,表示要显示隐藏变量。 回复: <?xml version="1.0" encoding="ISO-8859-1"?> <response xmlns="urn:debugger_protocol_v1" command="feature_set" transaction_id="1" feature="show_hidden" success="1"/> stdout -i 8 -c 1 stdout:命令名称,用于将输出发送到调试器的控制台。 -i 8:命令的唯一标识符,用于在调试器和 IDE 之间进行通信。 -c 1:输出的内容类型,表示输出的是文本内容。 回复: <?xml version="1.0" encoding="ISO-8859-1"?...

2023-03-29 · 2 分钟

Casbin的Model详解与使用

简介 文档:https://casbin.org/docs/zh-CN/overview Casbin 是干什么的文档说的很详细,就不在重复说了。相信很多人在看完文档之后,仍然是不知道 model.conf 和 policy.csv 是什么,看不懂里面的内容,有一种无从下手的感觉。 知识是有一个知识壁垒的,在你打破这个壁垒之前,你觉得很难,查资料看文章也是云里雾里的。但是在打破壁垒之后,掌握了这个知识在回头看,感觉真的好简单。 我查看了好几篇讲 Casbin 的文章,讲的都不是很通俗易懂,对于掌握了 Casbin 的人来看没什么,但是对于还不会的人看了还是有些云里雾里。所以我放弃了去搜索查看别人的经验,转而去读官方文档,在反反复复读了几遍文档之后终于掌握了 Casbin。不得不说在去学习一个新东西的时候,最好的办法就是去查看官方文档。接下来我会以不会 Casbin 的人的角度来尽可能通俗易懂的讲一讲 Casbin。 Model 与 Policy 接下来我们以 Linux 的文件系统权限为例来讲解 model.conf 和 policy.csv 。 语法 文档:https://casbin.org/docs/zh-CN/syntax-for-models Request 定义 不管哪个语言的 Casbin 都会提供一个 enforce 函数方法来校验是否有权限,[request_definition] 部分就定义了 enforce 函数的参数。 [request_definition] r = sub, obj, act sub, obj, act 经典三元组: 访问实体 (Subject),访问资源 (Object) 和访问方法 (Action),是可以自定义的。表示 enforce 函数需要按此顺序传入三个参数。 在 Linux 文件系统中: sub:代表用户 obj:代表访问的文件或文件夹 act:代表读、写或执行权限 在 RESTful 风格的 API 中:...

2022-10-25 · 3 分钟

多个docker-compose项目之间通信与环境架构

在讲多个 docker-compose 项目之间通信之前,想要先说一说我从刚使用 Docker 到目前为止遇到的一些问题与想法。 在刚学习 Docker 的时候,我相信很多人都跟我一样有过这种想法:我们的代码运行环境、MySQL、Redis 等服务是放到一个容器里面呢,还是放到多个容器里面呢?经过一番学习知道,Docker 官方是推荐将这些环境放置到多个容器中的,至于为什么就不详细说了,可以自行百度学习一下。 容器通信 但是当放到多个容器中,又会出现一个问题,我的 API 服务该怎么访问 MySQL、Redis 呢?有三种办法可以解决。 通过容器内 ip + 映射出的端口进行访问(不推荐) 通过 --link 链接另一个容器访问(不推荐) --link 只能在 docker run 一个容器时链接另一个已运行的容器,所以说该方法只能单向访问。 通过 network 将两个容器链接到同一个 network 中可以进行双向访问 docker-compose 这么看来第三种方式是最好的解决方案,但是当我们容器越来越多时,需要记住所有容器的 run 指令,将一个个的容器 run 起来,然后链接到同一个 network 中去,操作起来非常的麻烦。所以我更推荐使用 docker-compose 来编排管理多个容器。下面来编写一个 docker-compose.yml 文件演示一下。 编写接口 因为我们只是来演示一下容器之间的通信,使用 MySQL、Nginx 等容器反而更加的麻烦,所以我们使用 Golang 简单写一个接口用来构建一个演示的镜像。 package main import ( "flag" "github.com/gin-gonic/gin" ) func main() { name := flag.String("name", "", "") flag.Parse() r := gin....

2022-06-25 · 2 分钟

PHP百万数据导出Excel

背景 公司业务部门经常会需要导出各种数据进行分析,因为需要的数据模板多变,产品一直没有将其规划成系统功能,每次需要的数据都是手写 SQL 语句进行导出。在写了上万行 SQL 语句以后,我对这种体力劳动感觉到了厌烦,于是和领导申请,自己利用空闲时间规划开发了一个灵活配置、适用性强的导表系统。 使用技术 API 框架 Hyperf Web 框架 Ant Design Pro Excel 扩展 xlsWriter 优化 为了尽快实现功能,导出 Excel 功能是做的同步导出,但在我的设计中应该是异步导出,因此在后续的优化中引入了 RabbitMQ 消息队列实现异步导出功能。 因为不能将 Db 对象投递到消息队列中,所以投递过去的是 SQL 的预处理语句以及对应的变量,使用Db::select($sql, $bindings);执行 SQL 。然后尝试查询百万条数据,直接就内存溢出了。 vendor/hyperf/database/src/Connection.php 271 行 /** * Run a select statement against the database. */ public function select(string $query, array $bindings = [], bool $useReadPdo = true): array { return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { return []; } // For select statements, we'll simply execute the query and return an array // of the database result set....

2022-05-19 · 4 分钟

Docker中使用MySQL踩坑

需要使用到 MySQL ,打算使用 Docker 来部署,compose 来管理。原以为很简单,没想到还是有些坑的。 version: "3.7" services: mysql: image: mysql:8.0-oracle container_name: mysql ports: - "3306:3306" restart: always environment: # 密码 MYSQL_ROOT_PASSWORD: "root" # 创建默认数据库名 MYSQL_DATABASE: "test" 上面的写法就可以启动一个 MySQL 服务了,很简单。但是如果重新构建的话,数据就会丢失了,解决办法也很简单,挂载一下数据目录。 version: "3.7" services: mysql: image: mysql:8.0-oracle container_name: mysql ports: - "3306:3306" volumes: - ./data/mysql:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: "root" MYSQL_DATABASE: "test" 很好,MySQL 的数据已经挂载出来了,但是当重启 MySQL 容器的时候发现重启不了了,报错如下。 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.28-1.el8 started. chown: cannot dereference '/var/lib/mysql/mysql.sock': No such file or directory 根据报错信息是找不到挂载目录下的文件,猜测是权限原因引起的,加个权限试一试。...

2022-04-08 · 2 分钟

Go标准库time.Parse方法的时区问题

time.Parse方法解析时间字符串得到的 time 的时区为UTC,并不会自动使用系统的默认时区。 parse, _ := time.Parse("2006-01-02 15:04:05", "2022-03-30 13:37:03") //UTC 0 fmt.Println(parse.Zone()) //CST 28800 fmt.Println(time.Now().Zone()) 如果我们不想要UTC时区,需要别的时区。可以使用time.ParseInLocation方法自行设置时区。 loc, _ := time.LoadLocation("Asia/Shanghai") parse, _ := time.ParseInLocation("2006-01-02 15:04:05", "2022-03-30 13:37:03", loc) //CST 28800 fmt.Println(parse.Zone()) //CST 28800 fmt.Println(time.Now().Zone())

2022-03-30 · 1 分钟

alpine镜像设置时区

FROMalpineENV TZ=Asia/ShanghaiRUN echo 'http://mirrors.aliyun.com/alpine/v3.4/main/' > /etc/apk/repositories \ && apk --no-cache add tzdata zeromq \ && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \ && echo '$TZ' > /etc/timezone

2022-03-29 · 1 分钟

构建自己的go-gin-api脚手架(三)

Viper 地址:https://github.com/spf13/viper Viper 是适用于 Go 应用程序的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式。 文档 英文:可查看 Github 仓库的 README 文件 中文:可查看这篇文章的翻译 安装 go get github.com/spf13/viper 使用 新建配置文件/config/config.toml aaa = "111" bbb = "222" Viper 只需简单设置就可以读取到配置信息。 //设置文件路径 viper.AddConfigPath("/config") //设置文件名 viper.SetConfigName("config") //设置文件类型 viper.SetConfigType("toml") //读取配置文件 _ = viper.ReadInConfig() //监控配置文件变动 viper.WatchConfig() for { //输出所有配置 fmt.Println(viper.AllSettings()) time.Sleep(time.Second) } 多配置文件 随着项目开发,配置文件中的信息可能会越来越多,全部集中到一个文件中会变的难以管理。按功能分为不同的配置文件更易于管理,我们来自己实现一个多配置文件的方法。 方法一 使用MergeInConfig()方法将多个配置文件内容合并到一起。 在新建一个/config/router.toml配置文件 port = 8000 //设置文件路径 viper.AddConfigPath("/config") //设置文件名 viper.SetConfigName("config") //设置文件类型 viper.SetConfigType("toml") //读取配置文件 _ = viper.ReadInConfig() //设置第二个配置文件名称 viper.SetConfigName("router") //读取并合并已有配置 _ = viper....

2022-02-27 · 2 分钟

Dockerfile编写注意事项与技巧

1、多条指令应换行 ...RUN apt-get clean apt-get update...多条指令写在一行会当做一条指令执行,有可能后面的指令不执行或者报错。 应改为: ...RUN apt-get clean \ && apt-get update...2、忽略错误继续运行 我们在使用apt-get安装一个包时,常常会因为缺少依赖而安装失败,我们可以使用apt-get install -y -f --fix-missing命令来安装上一次安装失败所需要的依赖包,可以很方便的管理所以依赖,而不用我们手动按照依赖顺序把所有依赖包安装一遍,但是必须在安装失败后执行。Dockerfile 在构建过程中如果出现报错会立即退出构建,我们可以使用逻辑或||来忽略错误继续执行后面的语句。 ...# 下载Chrome安装包RUN wget -P /tmp https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ # 安装Chrome失败 && dpkg -i /tmp/google-chrome-stable_current_amd64.deb \ # 安装Chrome的依赖 && apt-get install -y -f --fix-missing \ # 再次安装Chrome && dpkg -i /tmp/google-chrome-stable_current_amd64.deb...上面的写法在 Chrome 安装失败时构建会退出,改为下面的写法就可以成功构建了。 ...# 下载Chrome安装包RUN wget -P /tmp https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ # 安装Chrome失败之后安装Chrome的依赖 && dpkg -i /tmp/google-chrome-stable_current_amd64.deb || apt-get install -y -f --fix-missing \ # 再次安装Chrome && dpkg -i /tmp/google-chrome-stable_current_amd64....

2022-01-26 · 1 分钟