You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

521 lines
30 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 特别放送 | IAM排障指南
你好,我是孔令飞。
今天我们更新一期特别放送作为加餐。在部署和使用IAM的过程中难免会出现一些异常(也称为故障、问题)。这时候就需要我们能够定位故障并修复故障。这里我总结了一些IAM的排障方法以及一些常见故障的解决方法供你参考。
## 如何排障?
首先,我们需要发现问题,然后定位问题。我们可能需要经过多轮分析排查才能定位到问题的根因,最后去解决问题。排障流程如下图所示:
![](https://static001.geekbang.org/resource/image/73/0f/7330d836e7c4b5052c79bbd365abdd0f.jpg?wh=2248x535)
如果想排查问题并解决问题,你还需要具备这两个基本能力:能够理解错误日志的内容;根据错误日志,找出解决方案。
我们举个例子来说吧。有以下错误:
```bash
[going@dev iam]$ mysql -h127.0.0.1 -uroot -p'iam59!z$'
bash: /usr/bin/mysql: 没有那个文件或目录
[going@dev iam]$
```
对于这个错误我们首先来理解错误内容mysql命令没有找到说明没有安装mysql或者安装mysql失败。
那么,我们的解决方案就是重新执行 [03讲](https://time.geekbang.org/column/article/378082) 中安装MariaDB的步骤
```bash
$ cd $IAM_ROOT
$ ./scripts/install/mariadb.sh iam::mariadb::install
```
接下来,我会以`iam-apiserver`服务为例,给你演示下具体如何排障并解决问题。
### 发现问题
要排障,首先我们需要发现问题。我们通常用下面这几种方式来发现问题。
* 检查服务状态启动iam-apiserver服务后执行`systemctl status iam-apiserver` 发现iam-apiserver启动失败即`Active`的值不为`active (running)`。
* 功能异常访问iam-apiserver服务功能异常或者报错例如接口返回值跟预期不一样等。
* 日志报错在iam-apiserver的日志中发现一些`WARN`、`ERROR`、`PANIC`、`FATAL`等级别的错误日志。
### 定位问题
发现问题之后,就需要我们定位出问题的根本原因。我们可以通过下面这三种方式来定位问题。
* 查看日志,它是最简单的排障方式。
* 使用Go调试工具Delve来定位问题。
* 添加Debug日志从程序入口处跟读代码在关键位置处打印Debug日志来定位问题。
在定位问题的过程中我们可以采用“顺藤摸瓜”的思路去排查问题。比如我们的程序执行流程是A -> B -> … -> N。其中A、B、N都可以理解为一个排查点。所谓的排查点就是需要在该处定位问题的点这些点可能是导致问题的根因所在。
在排障过程中你可以根据最上层的日志报错找到下一个排查点B。如果经过定位发现B没有问题那继续根据程序执行流程找下一个排查点排查问题。如此反复直到找到最终的排查点也就是出问题的根因NN即为Bug点。执行流程如下图所示
![](https://static001.geekbang.org/resource/image/cc/6d/cc26b83cb2177106695e1a9f7f09ae6d.jpg?wh=2248x931)
下面,我们来具体看看这三种定位问题的方法。
#### 查看日志定位问题
我们首先应该通过日志来定位问题,这是最简单高效的方式。要通过日志来定位问题,你不仅要会看日志,还要能读懂日志,也就是理解日志报错的原因。
下面我来具体讲解用这种方法定位问题的步骤。
**第一步,确保服务运行正常。**
你可以通过执行 `systemctl status` 命令来查看服务的运行状况:
```bash
$ systemctl status iam-apiserver
● iam-apiserver.service - IAM APIServer
Loaded: loaded (/etc/systemd/system/iam-apiserver.service; enabled; vendor preset: disabled)
Active: activating (auto-restart) (Result: exit-code) since Thu 2021-09-09 13:47:56 CST; 2s ago
Docs: https://github.com/marmotedu/iam/blob/master/init/README.md
Process: 119463 ExecStart=/opt/iam/bin/iam-apiserver --config=/etc/iam/iam-apiserver.yaml (code=exited, status=1/FAILURE)
Process: 119461 ExecStartPre=/usr/bin/mkdir -p /var/log/iam (code=exited, status=0/SUCCESS)
Process: 119460 ExecStartPre=/usr/bin/mkdir -p /data/iam/iam-apiserver (code=exited, status=0/SUCCESS)
Main PID: 119463 (code=exited, status=1/FAILURE)
```
可以看到,`Active`不是`active (running)`说明iam-apiserver服务没有正常运行。从上面输出中的`Process: 119463 ExecStart=/opt/iam/bin/iam-apiserver --config=/etc/iam/iam-apiserver.yaml (code=exited, status=1/FAILURE)`信息中,我们可以获取以下信息:
* iam-apiserver服务启动命令为`/opt/iam/bin/iam-apiserver --config=/etc/iam/iam-apiserver.yaml`。
* `/opt/iam/bin/iam-apiserver`加载的配置文件为`/etc/iam/iam-apiserver.yaml`。
* `/opt/iam/bin/iam-apiserver`命令执行失败退出码为1其进程ID为`119463`。
这里注意,`systemctl status`会将超过一定长度的行的后半部分用省略号替代,如果想查看完整的信息,可以追加`-l`参数,也就是`systemctl status -l`来查看。
既然iam-apiserver命令启动失败那我们就需要查看iam-apiserver启动时的日志看看有没有一些报错日志。
接下来,就进入**第二步,查看**`iam-apiserver`**运行日志。**
这里提一句如果你对systemd不了解也可以趁机恶补一波。你可以参考阮一峰大佬的两篇博客[Systemd 入门教程:命令篇](https://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html)和[Systemd 入门教程:实战篇](https://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html)。
那么如何查看呢我们有3种查看方式我在下面按优先级顺序排列了下。你在定位问题和查看日志时按优先级3选1即可1 > 2 > 3。
1. 通过`journalctl -u iam-apiserver`查看。
2. 通过iam-apiserver日志文件查看。
3. 通过console查看。
下面我来分别介绍下这三种查看方式。
先来看优先级最高的方式,通过`journalctl -u iam-apiserver`查看。
systemd 提供了自己的日志系统,称为 journal。我们可以使用`journalctl`命令来读取journal日志。`journalctl`提供了`-u`选项来查看某个 Unit 的日志,提供了`_PID`来查看指定进程ID的日志。在**第一步**中我们知道服务启动失败的进程ID为`119463`。执行以下命令来查看这次启动的日志:
```bash
$ sudo journalctl _PID=119463
-- Logs begin at Thu 2021-09-09 09:12:25 CST, end at Thu 2021-09-09 14:40:48 CST. --
...
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: 2021-09-09 13:47:56.727 INFO apiserver gorm@v1.21.12/gorm.go:202 mysql/mysql.go:75[error] faile>
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: 2021-09-09 13:47:56.727 FATAL apiserver apiserver/server.go:139 Failed to get cache instance: g>
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: github.com/marmotedu/iam/internal/apiserver.(*completedExtraConfig).New
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/server.go:139
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: github.com/marmotedu/iam/internal/apiserver.createAPIServer
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/server.go:66
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: github.com/marmotedu/iam/internal/apiserver.Run
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/run.go:11
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: github.com/marmotedu/iam/internal/apiserver.run.func1
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/app.go:46
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: github.com/marmotedu/iam/pkg/app.(*App).runCommand
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/src/github.com/marmotedu/iam/pkg/app/app.go:278
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: github.com/spf13/cobra.(*Command).execute
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/pkg/mod/github.com/spf13/cobra@v1.2.1/command.go:856
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: github.com/spf13/cobra.(*Command).ExecuteC
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/pkg/mod/github.com/spf13/cobra@v1.2.1/command.go:974
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: github.com/spf13/cobra.(*Command).Execute
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/pkg/mod/github.com/spf13/cobra@v1.2.1/command.go:902
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: github.com/marmotedu/iam/pkg/app.(*App).Run
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/src/github.com/marmotedu/iam/pkg/app/app.go:233
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: main.main
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/workspace/golang/src/github.com/marmotedu/iam/cmd/iam-apiserver/apiserver.go:24
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: runtime.main
Sep 09 13:47:56 VM-200-70-centos iam-apiserver[119463]: /home/going/go/go1.16.2/src/runtime/proc.go:225
lines 10-54/54 (END)
```
从上面的日志中,我们找到了服务启动失败的原因:`iam-apiserver`启动时,发生了`FATAL`级别的错误。到这里,你已经初步定位到问题原因了。
我们再来看通过iam-apiserver日志文件查看的方式。
作为一个企业级的实战项目iam-apiserver的日志当然是会记录到日志文件中的。在**第一步**中,我们通过`systemctl status iam-apiserver`输出的信息知道了iam-apiserver启动时加载的配置文件为`/etc/iam/iam-apiserver.yaml`。所以我们可以通过iam-apiserver的配置文件iam-apiserver.yaml中的`log.output-paths`配置项,查看记录日志文件的位置:
```yaml
log:
name: apiserver # Logger的名字
development: true # 是否是开发模式。如果是开发模式会对DPanicLevel进行堆栈跟踪。
level: debug # 日志级别优先级从低到高依次为debug, info, warn, error, dpanic, panic, fatal。
format: console # 支持的日志输出格式目前支持console和json两种。console其实就是text格式。
enable-color: true # 是否开启颜色输出true:是false:否
disable-caller: false # 是否开启 caller如果开启会在日志中显示调用日志所在的文件、函数和行号
disable-stacktrace: false # 是否在panic及以上级别禁止打印堆栈信息
output-paths: /var/log/iam/iam-apiserver.log,stdout # 支持输出到多个输出逗号分开。支持输出到标准输出stdout和文件。
error-output-paths: /var/log/iam/iam-apiserver.error.log # zap内部(非业务)错误日志输出路径,多个输出,逗号分开
```
可以看到iam-apiserver将日志分别记录到了`/var/log/iam/iam-apiserver.log`和`stdout`中。所以,我们可以通过查看`/var/log/iam/iam-apiserver.log`日志文件,来查看报错信息:
```bash
$ tail -25 /var/log/iam/iam-apiserver.log
...
2021-09-09 15:42:35.231 INFO apiserver server/genericapiserver.go:88 GET /version --> github.com/marmotedu/iam/internal/pkg/server.(*GenericAPIServer).InstallAPIs.func2 (10 handlers)
2021-09-09 15:42:35.232 INFO apiserver gorm@v1.21.12/gorm.go:202 mysql/mysql.go:75[error] failed to initialize database, got error dial tcp 127.0.0.1:3309: connect: connection refused
2021-09-09 15:42:35.232 FATAL apiserver apiserver/server.go:139 Failed to get cache instance: got nil cache server
github.com/marmotedu/iam/internal/apiserver.(*completedExtraConfig).New
/home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/server.go:139
github.com/marmotedu/iam/internal/apiserver.createAPIServer
/home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/server.go:66
github.com/marmotedu/iam/internal/apiserver.Run
/home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/run.go:11
github.com/marmotedu/iam/internal/apiserver.run.func1
/home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/app.go:46
github.com/marmotedu/iam/pkg/app.(*App).runCommand
/home/going/workspace/golang/src/github.com/marmotedu/iam/pkg/app/app.go:278
github.com/spf13/cobra.(*Command).execute
/home/going/workspace/golang/pkg/mod/github.com/spf13/cobra@v1.2.1/command.go:856
github.com/spf13/cobra.(*Command).ExecuteC
/home/going/workspace/golang/pkg/mod/github.com/spf13/cobra@v1.2.1/command.go:974
github.com/spf13/cobra.(*Command).Execute
/home/going/workspace/golang/pkg/mod/github.com/spf13/cobra@v1.2.1/command.go:902
github.com/marmotedu/iam/pkg/app.(*App).Run
/home/going/workspace/golang/src/github.com/marmotedu/iam/pkg/app/app.go:233
main.main
/home/going/workspace/golang/src/github.com/marmotedu/iam/cmd/iam-apiserver/apiserver.go:24
runtime.main
/home/going/go/go1.16.2/src/runtime/proc.go:225
```
我们再来看最后一种查看方式通过console查看。
当然我们也可以直接通过console来看日志这就需要我们在Linux终端前台运行iam-apiserver在**第一步**中,我们已经知道了启动命令):
```bash
$ sudo /opt/iam/bin/iam-apiserver --config=/etc/iam/iam-apiserver.yaml
...
2021-09-09 15:47:00.660 INFO apiserver server/genericapiserver.go:88 GET /debug/pprof/mutex --> github.com/gin-contrib/pprof.pprofHandler.func1 (10 handlers)
2021-09-09 15:47:00.660 INFO apiserver server/genericapiserver.go:88 GET /debug/pprof/threadcreate --> github.com/gin-contrib/pprof.pprofHandler.func1 (10 handlers)
2021-09-09 15:47:00.660 INFO apiserver server/genericapiserver.go:88 GET /version --> github.com/marmotedu/iam/internal/pkg/server.(*GenericAPIServer).InstallAPIs.func2 (10 handlers)
2021-09-09 15:47:00.661 INFO apiserver gorm@v1.21.12/gorm.go:202 mysql/mysql.go:75[error] failed to initialize database, got error dial tcp 127.0.0.1:3309: connect: connection refused
2021-09-09 15:47:00.661 FATAL apiserver apiserver/server.go:139 Failed to get cache instance: got nil cache server
github.com/marmotedu/iam/internal/apiserver.(*completedExtraConfig).New
/home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/server.go:139
github.com/marmotedu/iam/internal/apiserver.createAPIServer
/home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/server.go:66
github.com/marmotedu/iam/internal/apiserver.Run
/home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/run.go:11
github.com/marmotedu/iam/internal/apiserver.run.func1
/home/going/workspace/golang/src/github.com/marmotedu/iam/internal/apiserver/app.go:46
github.com/marmotedu/iam/pkg/app.(*App).runCommand
/home/going/workspace/golang/src/github.com/marmotedu/iam/pkg/app/app.go:278
github.com/spf13/cobra.(*Command).execute
/home/going/workspace/golang/pkg/mod/github.com/spf13/cobra@v1.2.1/command.go:856
github.com/spf13/cobra.(*Command).ExecuteC
/home/going/workspace/golang/pkg/mod/github.com/spf13/cobra@v1.2.1/command.go:974
github.com/spf13/cobra.(*Command).Execute
/home/going/workspace/golang/pkg/mod/github.com/spf13/cobra@v1.2.1/command.go:902
github.com/marmotedu/iam/pkg/app.(*App).Run
/home/going/workspace/golang/src/github.com/marmotedu/iam/pkg/app/app.go:233
main.main
/home/going/workspace/golang/src/github.com/marmotedu/iam/cmd/iam-apiserver/apiserver.go:24
runtime.main
/home/going/go/go1.16.2/src/runtime/proc.go:225
```
通过上面这3种查看方式我们均能初步定位到服务异常的原因。
#### 使用Go调试工具Delve来定位问题
查看日志是最简单的排障方式,通过查看日志,我们可能定位出问题的根本原因,这种情况下问题就能得到快速的解决。但有些情况下,我们通过日志并不一定能定位出问题,例如:
* 程序异常,但是没有错误日志。
* 日志有报错,但只能判断问题的面,还不能精准找到问题的根因。
遇到上面这两种情况我们都需要再进一步地定位问题。这时候我们可以使用Delve调试工具来尝试定位问题。Delve工具的用法你可以参考 [Delve使用详解](https://github.com/marmotedu/geekbang-go/blob/master/Delve%E4%BD%BF%E7%94%A8%E8%AF%A6%E8%A7%A3.md)。
#### 添加Debug日志定位问题
如果使用 Delve 工具仍然没有定位出问题接下来你可以尝试最原始的方法添加Debug日志来定位问题。这种方法具体可以分为两个步骤。
**第一步在关键代码段添加Debug日志。**
你需要根据自己对代码的理解来决定关键代码段。如果不确定哪段代码出问题可以从请求入口处添加Debug日志然后跟着代码流程一步步往下排查并在需要的地方添加Debug日志。
例如,通过排查日志,我们定位到`internal/apiserver/server.go:139`位置的代码导致程序FATALFATAL原因是`Failed to get cache instance: got nil cache server`。`cache server`是`nil`,说明`cache server`没有被初始化。查看`cache server`初始化函数:
```go
func GetCacheInsOr(store store.Factory) (*Cache, error) {
if store != nil {
once.Do(func() {
cacheServer = &Cache{store}
})
}
if cacheServer == nil {
return nil, fmt.Errorf("got nil cache server")
}
return cacheServer, nil
}
```
我们不难分析出,是`store == nil`导致`cacheServer`没有被初始化。再来看下store的初始化代码并加一些Debug日志如下图所示
![图片](https://static001.geekbang.org/resource/image/cc/15/cc50c340e4ff0e5401b3d89430456b15.png?wh=1669x1025)
我们添加完Debug代码后就可以重新编译并运行程序了。
这里有个小技巧可以在错误返回的位置添加Debug日志这样能大概率帮助你定位到出错的位置例如
```go
if err != nil {
log.Debugf("DEBUG POINT - 1: %v", err)
return err
}
```
**第二步,重新编译源码,并启动。**
这里为了调试、看日志方便我们直接在Linux终端的前端运行iam-apiserver
```bash
$ sudo /opt/iam/bin/iam-apiserver --config=/etc/iam/iam-apiserver.yaml
```
查看我们添加的Debug日志打印的内容如下图所示
![图片](https://static001.geekbang.org/resource/image/61/03/61f31a4b9e45ed9079470e928f7d3b03.png?wh=1920x265)
从Debug日志中可以看到用来创建MySQL实例的端口是错误的正确的端口应该是`3306`,而不是`3309`。MySQL服务器的端口是在iam-apiserver.yaml中配置的。修改iam-apiserver.yaml为正确的配置并启动
```bash
$ sudo /opt/iam/bin/iam-apiserver --config=/etc/iam/iam-apiserver.yaml
```
再次查看console日志如下图所示
![图片](https://static001.geekbang.org/resource/image/f7/9d/f72b766b7504016259bef04eb03dac9d.png?wh=1920x271)
可以看到问题已经修复,`dbIns`不为`nil`,程序正常运行:
```bash
$ systemctl status iam-apiserver
● iam-apiserver.service - IAM APIServer
Loaded: loaded (/etc/systemd/system/iam-apiserver.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2021-09-09 20:48:18 CST; 17s ago
Docs: https://github.com/marmotedu/iam/blob/master/init/README.md
Process: 255648 ExecStartPre=/usr/bin/mkdir -p /var/log/iam (code=exited, status=0/SUCCESS)
Process: 255647 ExecStartPre=/usr/bin/mkdir -p /data/iam/iam-apiserver (code=exited, status=0/SUCCESS)
Main PID: 255650 (iam-apiserver)
Tasks: 5 (limit: 23724)
Memory: 7.3M
CGroup: /system.slice/iam-apiserver.service
└─255650 /opt/iam/bin/iam-apiserver --config=/etc/iam/iam-apiserver.yaml
```
在这里,`Active`为`active (running)`状态。
因为这些Debug日志能够协助你定位问题从侧面说明这些日志是有用的所以你可以保留这些Debug日志调用代码。
### 解决问题
在定位问题阶段,我们已经找到了问题的原因,接下来就可以根据自己对业务、底层代码实现的掌握和理解,修复这个问题了。至于怎么修复,你需要结合具体情况来判断,并没有统一的流程和方法论,这里就不多介绍了。
上面我介绍了排查问题的思路和方法。接下来我来向你展示9个在部署和使用IAM系统时容易遇到的问题并提供解决方法。这些问题基本上都是由服务器环境引起的。
## IAM常见故障及解决办法
**问题一:**安装neovim`No match for argument: neovim` 错误。
解决方法是安装 EPEL 源:
```bash
$ sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
```
**问题二:**安装protoc-gen-go失败超时、报错等
这个故障出现,可能是因为你当前服务器所在的网络环境无法访问`github.com`,或者访问`github.com`速度太慢。
解决方法是手动编译安装,方法如下:
```bash
$ git clone --depth 1 https://github.com/golang/protobuf $GOPATH/src/github.com/golang/protobuf
$ cd $GOPATH/src/github.com/golang/protobuf/protoc-gen-go
$ go install -v .
```
**问题三:**遇到`xxx: permission denied`这类的错误。
出现这种错误,是因为你没有权限执行当前的操作。解决方法是排查自己是否有权限执行当前操作。如果没有权限,需要你切换到有权限的用户,或者放弃执行当前操作。
为了说明问题,这里我举一个错误例子,并给出排查思路。例子的错误日志如下:
```bash
[going@VM-8-9-centos /]$ go get -u github.com/golang/protobuf/protoc-gen-go
go: could not create module cache: mkdir /golang: permission denied
[going@VM-8-9-centos /]$ sudo go get -u github.com/golang/protobuf/protoc-gen-go
sudo: go: command not found
```
上述错误中, 一共报了两个错误,分别是`mkdir /golang: permission denied`和`sudo: go: command not found`。我们先来看`mkdir /golang: permission denied`错误。
通过命令行提示符`$`可以知道,当前登陆用户是普通用户;通过报错`mkdir /golang: permission denied`可以知道`go get -u github.com/golang/protobuf/protoc-gen-go`命令底层执行了`mkdir /golang`,因为普通用户没有写`/` 目录的权限,所以会报权限错误。解决方法是切换到用户的目录下,执行`go get -u`命令。
我们再来看下`sudo: go: command not found`错误。`sudo`命令会将命令执行的环境切换到`root`用户,`root`用户显然是没有安装`go`命令的,所以会导致`command not found`错误。解决方式是去掉 `sudo` ,直接执行 `$ go get -u xxx`
**问题四:**VimIDE使用过程中报各类错误。
这里的报错原因跟环境有关系安装VimIDE时的系统环境、包的版本等等都可能会导致使用VimIDE报错。因为错误类型太多没法一一说明所以我建议你忽略这些错误其实完全不影响后面的学习。
**问题五:**访问iam-authz-server的`/v1/authz`接口报`{"code":100202,"message":"Signature is invalid"}`。
这时可能是签发的Token有问题建议重新执行以下5个步骤
1. 重新登陆系统,并获取访问令牌:
```bash
$ token=`curl -s -XPOST -H'Content-Type: application/json' -d'{"username":"admin","password":"Admin@2021"}' http://127.0.0.1:8080/login | jq -r .token`
```
如果没有安装`jq`命令,可以执行`sudo yum -y install jq`命令来安装。
2. 创建授权策略:
```bash
$ curl -s -XPOST -H"Content-Type: application/json" -H"Authorization: Bearer $token" -d'{"metadata":{"name":"authztest"},"policy":{"description":"One policy to rule them all.","subjects":["users:<peter|ken>","users:maria","groups:admins"],"actions":["delete","<create|update>"],"effect":"allow","resources":["resources:articles:<.*>","resources:printer"],"conditions":{"remoteIPAddress":{"type":"CIDRCondition","options":{"cidr":"192.168.0.1/16"}}}}}' http://127.0.0.1:8080/v1/policies
```
3. 创建密钥并从命令的输出中提取secretID 和 secretKey
```bash
$ curl -s -XPOST -H"Content-Type: application/json" -H"Authorization: Bearer $token" -d'{"metadata":{"name":"authztest"},"expires":0,"description":"admin secret"}' http://127.0.0.1:8080/v1/secrets
{"metadata":{"id":23,"name":"authztest","createdAt":"2021-04-08T07:24:50.071671422+08:00","updatedAt":"2021-04-08T07:24:50.071671422+08:00"},"username":"admin","secretID":"ZuxvXNfG08BdEMqkTaP41L2DLArlE6Jpqoox","secretKey":"7Sfa5EfAPIwcTLGCfSvqLf0zZGCjF3l8","expires":0,"description":"admin secret"}
```
4. 生成访问 iam-authz-server 的 Token
iamctl 提供了 `jwt sigin` 命令,你可以根据 `secretID``secretKey` 签发 Token方便你使用。签发Token的具体命令如下
```bash
$ iamctl jwt sign ZuxvXNfG08BdEMqkTaP41L2DLArlE6Jpqoox 7Sfa5EfAPIwcTLGCfSvqLf0zZGCjF3l8 # iamctl jwt sign $secretID $secretKey
eyJhbGciOiJIUzI1NiIsImtpZCI6Ilp1eHZYTmZHMDhCZEVNcWtUYVA0MUwyRExBcmxFNkpwcW9veCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJpYW0uYXV0aHoubWFybW90ZWR1LmNvbSIsImV4cCI6MTYxNzg0NTE5NSwiaWF0IjoxNjE3ODM3OTk1LCJpc3MiOiJpYW1jdGwiLCJuYmYiOjE2MTc4Mzc5OTV9.za9yLM7lHVabPAlVQLCqXEaf8sTU6sodAsMXnmpXjMQ
```
5. 测试资源授权是否通过:
```bash
$ curl -s -XPOST -H'Content-Type: application/json' -H'Authorization: Bearer eyJhbGciOiJIUzI1NiIsImtpZCI6Ilp1eHZYTmZHMDhCZEVNcWtUYVA0MUwyRExBcmxFNkpwcW9veCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJpYW0uYXV0aHoubWFybW90ZWR1LmNvbSIsImV4cCI6MTYxNzg0NTE5NSwiaWF0IjoxNjE3ODM3OTk1LCJpc3MiOiJpYW1jdGwiLCJuYmYiOjE2MTc4Mzc5OTV9.za9yLM7lHVabPAlVQLCqXEaf8sTU6sodAsMXnmpXjMQ' -d'{"subject":"users:maria","action":"delete","resource":"resources:articles:ladon-introduction","context":{"remoteIPAddress":"192.168.0.5"}}' http://127.0.0.1:9090/v1/authz
{"allowed":true}
```
**问题六:**执行`iamctl user list`报`error: {"code":100207,"message":"Permission denied"}`。
出现这种情况,可能是密码没有配置正确。
你可以看下`$HOME/.iam/iamctl.yaml`配置文件中的用户名和密码配置的是不是admin以及admin的密码是否是`Admin@2021`。
**问题七:**在创建用户时报`{"code":100101,"message":"Database error"}`错误。
出现这种情况,可能是用户名重了,建议换个新的用户名再次创建。
**问题八:**报`No such file or directory`、`command not found`、`permission denied`错误。
遇到这类错误,要根据提示排查和解决问题。
* `No such file or directory`:确认文件是否存在,不存在的原因是什么。
* `command not found`:确认命令是否存在,如果不存在,可以重新安装命令。
* `permission denied`:确认是否有操作权限,如果没有,要切换到有权限的用户或者目录。
**问题九:**报`iam-apiserver.service`、`/opt/iam/bin/iam-apiserver`、`/etc/iam/iam-apiserver.yaml`文件不存在。
我来介绍下这些文件的作用。
* `/etc/systemd/system/iam-apiserver.service`iam-apiserver的sysmted Unit文件。
* `/opt/iam/bin/iam-apiserver`iam-apiserver的二进制启动命令。
* `/etc/iam/iam-apiserver.yaml`iam-apiserver的配置文件。
如果某个文件不存在,那就需要你重新安装这些文件。我来分别介绍这三个文件的安装方法。
`/etc/systemd/system/iam-apiserver.service`安装方法:
```bash
$ cd $IAM_ROOT
$ ./scripts/genconfig.sh scripts/install/environment.sh init/iam-apiserver.service > iam-apiserver.service
$ sudo mv iam-apiserver.service /etc/systemd/system/
```
`/opt/iam/bin/iam-apiserver`安装方法:
```bash
$ cd $IAM_ROOT
$ source scripts/install/environment.sh
$ make build BINS=iam-apiserver
$ sudo cp _output/platforms/linux/amd64/iam-apiserver ${IAM_INSTALL_DIR}/bin
```
`/etc/iam/iam-apiserver.yaml`安装方法:
```bash
$ cd $IAM_ROOT
$ ./scripts/genconfig.sh scripts/install/environment.sh configs/iam-apiserver.yaml > iam-apiserver.yaml
$ sudo mv iam-apiserver.yaml ${IAM_CONFIG_DIR}
```
## 总结
这一讲,我以`iam-apiserver`服务为例,向你介绍了排障的基本流程:发现问题 -> 定位问题 -> 解决问题。
你可以通过三种方式来发现问题。
* 检查服务状态启动iam-apiserver服务后执行`systemctl status iam-apiserver` 发现iam-apiserver启动失败即`Active`的值不为`active (running)`。
* 功能异常访问iam-apiserver服务功能异常或者报错例如接口返回值跟预期不一样接口报错。
* 日志报错在iam-apiserver的日志中发现一些`WARN`、`ERROR`、`PANIC`、`FATAL`等高级别的错误日志。
发现问题之后你可以通过查看日志、使用Go调试工具Delve和添加Debug日志这三种方式来定位问题。
* 查看日志:查看日志是最简单的排障方式。
* 使用Go调试工具Delve来定位问题。
* 添加Debug日志从程序入口处跟读代码在关键位置处打印Debug日志来定位问题。
找到问题根因之后,就要解决问题。你需要根据自己对业务、底层代码实现的掌握和理解,解决这个问题。
最后我向你展示了9个在部署和使用IAM系统时容易遇到的问题并提供了解决方法希望能给你一些切实的帮助。
## 课后练习
1. 思考下如何查找iam-apiserver的systemd Unit文件的路径
2. 执行以下命令:
```bash
$ token=`curl -s -XPOST -H'Content-Type: application/json' -d'{"username":"admin","password":"Admin@2021"}' http://127.0.0.1:8080/login | jq -r .token`
$ echo $token
```
可以获取`token`,但发现`token`值为空。请给出你的排障流程和方法。
欢迎你在留言区与我交流讨论,我们下一讲见。