前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Gitlab CI/CD 实践三:Docker 安装 Gitlab Runner

Gitlab CI/CD 实践三:Docker 安装 Gitlab Runner

作者头像
Yuyy
发布2024-08-18 16:20:58
780
发布2024-08-18 16:20:58
举报
文章被收录于专栏:yuyy.info技术专栏

问题现象

当前有个目录 a,需要对其创建一个软链接 b。

代码语言:javascript
复制
   tree
   .
   `-- a
       |-- a1.txt
       `-- a2.txt

   1 directory, 2 files

第一次执行ln -s a b

成功执行,符合预期

代码语言:javascript
复制
tree
.
|-- a
|   |-- a1.txt
|   `-- a2.txt
`-- b -> a

2 directories, 2 files

通过软链能正确访问到 a1.txt

代码语言:javascript
复制
ls -l b/a1.txt
-rw-r--r-- 1 root root 0 Aug 17 02:08 b/a1.txt

第二次执行ln -s a b

成功执行,不符合预期

代码语言:javascript
复制
tree
.
|-- a
|   |-- a -> a
|   |-- a1.txt
|   `-- a2.txt
`-- b -> a

2 directories, 3 files

此时软链接 b 已存在,我的预期是执行失败,或者覆盖软链接 b,但实际上在 a 下创建了一个软链接 a,这是第一个问题

第二个问题,为什么新创建的软链接文件名是 a,而不是 b

第三个问题,通过新创建的软链,无法访问到 a1.txt

代码语言:javascript
复制
ls -l a/a/a1.txt
ls: cannot access 'a/a/a1.txt': Too many levels of symbolic links

第三次执行ln -s a b

执行失败,提示软链接 b/a 已存在。

代码语言:javascript
复制
ln -s a b
ln: failed to create symbolic link 'b/a': File exists

第四个问题,为什么第二次执行都没报错,第三次却报错了?到底能不能重复执行?

软链接原理

先介绍下文件系统。

磁盘布局

在 VSFS(Very SimpleFile System,简单文件系统)中

superblock

超级块里存储了文件系统信息,inode 数量,数据块数量,inode 区域的开始位置等信息。

inode bitmap

用 bitmap 来储存 inode 区域的分配情况。当写入一个新文件时,需要创建一个 inode,保存在 inode 空闲区域。如果直接扫描 inode 区域,寻找空闲位置,是非常耗费 IO 性能的。而通过 inode bitmap,只需要一次 IO,就能知道整个 inode 区域的分配情况。再在内存中遍历下,得到一个空闲的 inode 号。通过 inode 号,就能找到 inode 区域中对应位置。

data bitmap

和 inode bitmap 功能类似。

inode

inode 是index node(索引节点)的缩写,因为inode号用于索引磁盘上的inode数组,以便查找该inode号对应的inode。

inode 用于保存文件的元数据,例如文件类型(例如,常规文件、目录等)、大小、分配给它的块数、保护信息(如谁拥有该文件以及谁可以访问它)、一些时间信息(包括文件创建、修改或上次访问的时间文件下),以及有关其数据块驻留在磁盘上的位置的信息(如某种类型的指针)。

注意,inode 里没有文件名,在文件系统中,文件的路径是由目录文件构成的。每个目录在数据块区域是一个目录文件,包含这个目录下的文件名、文件的 inode 号、这条记录的长度、文件名字符串的长度等信息。所以通过硬链接或软链接,可以使用不同的路径访问到同一个文件。 延伸想想同一个文件系统下,mv 命令是如何工作的。

使用 df -i 命令查看 inode 的使用量

代码语言:javascript
复制
df -i
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
overlay        3907584 119123 3788461    4% /
tmpfs          1003656     17 1003639    1% /dev
shm            1003656      1 1003655    1% /dev/shm
/dev/vda1      3907584 119123 3788461    4% /etc/hosts
tmpfs          1003656      1 1003655    1% /sys/firmware

小文件太多,可能造成磁盘没满,但是 inode 用完了,导致无法创建文件。可通过上诉命令检查。

拿上面的目录举例

代码语言:javascript
复制
tree
.
`-- a
    |-- a1.txt
    `-- a2.txt

1 directory, 2 files

下图左边部分在磁盘的 inode 区域,右边部分在磁盘的数据块区域。

执行软链命令后

ln -s a b

代码语言:javascript
复制
tree
.
|-- a
|   |-- a1.txt
|   `-- a2.txt
`-- b -> a

2 directories, 2 files

创建软链接执行了下列动作

  1. 修改当前目录对应的目录文件,增加软链接 b 的信息
  2. 创建软链接 b 的 inode 注意,没有磁盘指针,软链接是不会在数据块区域分配空间。 另外指向目标路径是个相对路径,和创建软链接的方式有关。

软链接相对路径问题

准备 case

代码语言:javascript
复制
echo `date` > c.txt
mkdir d
ln -s c.txt d/c.txt

查看目录结果

代码语言:javascript
复制
tree
.
|-- c.txt
`-- d
    `-- c.txt -> c.txt

查看软链报错

代码语言:javascript
复制
cat d/c.txt
cat: d/c.txt: Too many levels of symbolic links

使用 stat 查看软链信息

代码语言:javascript
复制
stat d/c.txt
  File: d/c.txt -> c.txt
  Size: 5           Blocks: 0          IO Block: 4096   symbolic link
Device: 3bh/59d Inode: 533547      Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2024-08-17 08:27:32.335451007 +0000
Modify: 2024-08-17 08:27:12.832303012 +0000
Change: 2024-08-17 08:27:12.832303012 +0000
 Birth: -

d/c.txt -> c.txt 这是一个相对路径,相对于软链本身,那么这个软链指向的是自己,所以报错:“Too many levels of symbolic links”。

ln 命令 help 信息里也有说明相对路径的情况。

代码语言:javascript
复制
ln --help
Usage: ln [OPTION]... [-T] TARGET LINK_NAME
  or:  ln [OPTION]... TARGET
  or:  ln [OPTION]... TARGET... DIRECTORY
  or:  ln [OPTION]... -t DIRECTORY TARGET...
In the 1st form, create a link to TARGET with the name LINK_NAME.
In the 2nd form, create a link to TARGET in the current directory.
In the 3rd and 4th forms, create links to each TARGET in DIRECTORY.
Create hard links by default, symbolic links with --symbolic.
By default, each destination (name of new link) should not already exist.
When creating hard links, each TARGET must exist.  Symbolic links
can hold arbitrary text; if later resolved, a relative link is
interpreted in relation to its parent directory.

如何避免此问题?

  1. 使用绝对路径。
  2. 创建软链时,先进入到即将创建的软链的所在目录,然后被软链文件使用相对于当前目录的路径。

解释问题现象

第一个问题

为什么第二次执行ln -s a b时,没有覆盖软链接 b,而是在 a 下创建了一个软链接 a?

第一次创建软链后,生成了软链 b。在第二次创建软链时,会判断目标路径是否是存在的目录,此时目标路径是 b,它指向了 a,所以目标路径是存在的 a,那么就在 a 目录下创建软链。也就是上面ln --help信息里的第三种和第四种用法。

第二个问题

为什么新创建的软链接文件名是 a,而不是 b?

创建软链的目标路径是目录时,就在该目录下创建自身的同名软链,指向自己。

第三个问题

通过新创建的软链,无法访问到 a1.txt。

原因是上文提到的软链相对路径问题,检查 a 目录下的软链 a,看看它指向哪里。

代码语言:javascript
复制
stat a/a
  File: a/a -> a
  Size: 1           Blocks: 0          IO Block: 4096   symbolic link
Device: 3bh/59d Inode: 533417      Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2024-08-17 03:18:11.949193005 +0000
Modify: 2024-08-17 03:18:10.232193004 +0000
Change: 2024-08-17 03:18:10.232193004 +0000
 Birth: -

发现它指向的是自己,而不是预期的父目录,所以访问它时报错:“Too many levels of symbolic links”。

第四个问题

为什么第二次执行都没报错,第三次却报错了?到底能不能重复执行?

原因是软链目录是存在的目录时,就在该目录下创建自身的同名软链,指向自己。而第二次执行时已经创建了这个软链 a/a,再次创建时就会报错:“ File exists”。

解决

方案一

创建软链前先检查软链是否存在,存在的话检查是否是指向预期的源文件。

方案二

使用 ln 命令的选项 n。

-n, --no-dereference treat LINK_NAME as a normal file if it is a symbolic link to a directory

达到的效果是在第二次创建软链时,因为软链 b 已存在,报错。而不是在 b 软链指向的 a 目录下,再去创建一个软链指向自己。

代码语言:javascript
复制
ln -sn a b
ln: failed to create symbolic link 'b': File exists

参考

  1. 《操作系统导论》
  2. https://linuxconfig.org/how-to-fix-too-many-levels-of-symbolic-links-error
  3. https://unix.stackexchange.com/questions/588021/why-does-ln-s-create-a-directory-if-soft-link-exists?rq=1
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-8-17 1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题现象
    • 第一次执行ln -s a b
      • 第二次执行ln -s a b
        • 第三次执行ln -s a b
        • 软链接原理
          • 磁盘布局
            • inode
              • 拿上面的目录举例
                • 执行软链命令后
                  • 软链接相对路径问题
                  • 解释问题现象
                    • 第一个问题
                      • 第二个问题
                        • 第三个问题
                          • 第四个问题
                          • 解决
                            • 方案一
                              • 方案二
                              • 参考
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档