Skip to main content

· 3 min read
CheverJohn

Observability (monitoring functionality) has always played an important role in system maintenance. A good monitoring system can help engineers quickly understand the status of services running in production environments and can locate problems or give early warning of anomalies when they occur.

Prometheus is a leading open-source project focused on metrics and alerting that has changed the way the world does monitoring and observability. And Apache APISIX Ingress Controller has enhanced its support for Prometheus Metrics in recent releases, adding a new feature for use in conjunction with the public-api plugin. This article will introduce how to configure public-api to protect Prometheus to collect Apache APISIX Ingress Controller's Metrics data.

· 10 min read
CheverJohn

首先讲一下为啥我要做一个 yubikey,为了帅啊! 人活一世,哪能不帅一点呢?想想当你在提交你的 commit 的时候,掏出你的 yubikey(一款硬件加解密器)的时候,然后快速地在你的终端里输入一些命令(如下),然后你就可以在你的 GitHub 上看到一条 verified 的 commit,贼拉帅,如下:

github_gpg

科普引导

首先上一篇“约伊兹的萌狼乡手札 约伊兹的萌狼乡手札”大佬的一篇科普博客。从我们为什么需要密码技术,到实践上手一个gpg 加解密配置。讲得还算是很清楚啦!

然后是yubikey 的官网,重置密码一类的全在这里头,我这两天遇到的坑也大多可以从这边找到解决方法。yubikey's website,里边还有很多优秀的实践操作。可以学习!

还有这个开源的 gpg 软件,里边的文档也可以参考哈。 GnuPG

最重要的链接

本篇博客主要实践是按照 GitHub 上这个项目的指导完成的。这篇文章其实和今天的方案也不太符合,因为他是需要两枚 yubikey 的最佳实践!当然因为我穷啦,只配拥有一枚 yubikey。等下次再买一枚,构建主密钥保护子密钥的系统。 https://github.com/YubicoLabs/sign-git-commits-yubikey 再将链接放清楚一些!

一些杂七杂八的链接

https://www.hanselman.com/blog/how-to-setup-signed-git-commits-with-a-yubikey-neo-and-gpg-and-keybase-on-windows

https://andrewmatveychuk.com/how-to-sign-you-commits-with-gpg-git-and-yubikey/

https://den.dev/blog/signing-github-commits-yubikey/

还有这个最全的yubikey的命令集: https://github.com/drduh/YubiKey-Guide

这篇文章也不错的 https://www.engineerbetter.com/blog/yubikey-signed-commits/

https://medium.com/@antagonist/sign-your-git-commits-using-your-yubikey-gpg-8118fef12ee5

以上是我看过的基本上所有的文章,有好有坏,好的我都用中文额外说了一下。

下面是 youtube 视频

跟随这个视频你能实现 verified,但是无法正常实现最终目的——使用 yubikey 签名 commit。 https://www.youtube.com/watch?v=Y3mLBTCiccs&t=5s

正式开始啦

你需要具备的东西

一台 macOS 的电脑 一个 yubikey 一个 GitHub 账号 拥有基本的计算机素养

那么首先你需要注意的你是什么系统,这边我拿我的 macOS 来做演示哈。

开始流程

安装基本软件

macOS 需要安装 Yubikey manager 和 GnuPG 以及 Pinentry

YubiKey Manager
GnuPG

The easiest way to install GnuPG on macOS is using Homebrew:

Note: The latest version of GnuPG (3.2.1 at the time of writing) on Homebrew works fine.

$ brew install gnupg
Pinentry

It’s recommended to install the graphical pinentry program for macOS.

$ brew install pinentry-mac

Add to your ~/.gnupg/gpg-agent.conf file(这边需要注意的是,是在文件里添加下面一行,不是傻乎乎的在终端一直输入下面的东西):

pinentry-program /usr/local/bin/pinentry-mac

Add to your ~/.gnupg/scdaemon.conf file:

disable-ccid (From the man page: Disable the integrated support for CCID compliant readers. This allows falling back to one of the other drivers even if the internal CCID driver can handle the reader.)

生成密钥

生成之前先更改密钥的加解密算法

Changing to better defaults

We want to make sure we’re using the strongest key types that are available for GPG. For our purposes, we need to use RSA keys for all key types. Set the key size to the maximum supported by the YubiKey (4096 bits).

gpg/card> key-attr
Changing card key attribute for: Signature key
Please select what kind of key you want:
(1) RSA
(2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits
Changing card key attribute for: Encryption key
Please select what kind of key you want:
(1) RSA
(2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits
Changing card key attribute for: Authentication key
Please select what kind of key you want:
(1) RSA
(2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits
开始生成密钥

命令如下

gpg --card-edit

然后你将进入到 yubikey 的配置程序

gpg/card> admin
Admin commands are allowed

你可以选择设置 yubikey 的 PIN 和 Admin PIN

gpg/card> passwd
gpg: OpenPGP card no. D2760001240102010006078005150000 detected

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 1
<< Enter PIN. (Default is 123456) >>
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 3
<< Enter admin PIN. (Default is 12345678) >>

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? Q

然后生成你的 gpg 混合加密系统的三个加密密钥

gpg/card> generate
Make off-card backup of encryption key? (Y/n) n

Please note that the factory settings of the PINs are
PIN = '123456' Admin PIN = '12345678'
You should change them using the command --change-pin

Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: You
Name must be at least 5 characters long
Real name: You McEngineer
Email address: you@example.com
Comment:
You selected this USER-ID:
"You McEngineer <you@example.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
gpg: key 109F2428DD97A597 marked as ultimately trusted
gpg: revocation certificate stored as 'C:/Users/you/AppData/Roaming/gnupg/openpgp-revocs.d\2F28DCB202028A5A2FE5A45D109F2428DD97A597.rev'
public and secret key created and signed.

list 命令列出所有的 密钥

gpg/card> list

Reader ...........: Yubico YubiKey OTP CCID 0
Application ID ...: D2760001240103030006000152110000
Version ..........: 3.3
Manufacturer .....: Yubico
Serial number ....: 00015211
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 4
KDF setting ......: on
Signature key ....: 2F28 DCB2 0202 8A5A 2FE5 A45D 109F 2428 DD97 A597
created ....: 2019-12-03 01:21:36
Encryption key....: 4E14 0FFF B296 D2D5 6CD0 A654 C821 9CCE 0DAB FC09
created ....: 2019-12-03 01:21:36
Authentication key: 529E FBFD BF0C 5908 79A5 4FAB 23DC 6210 FD32 B9BF
created ....: 2019-12-03 01:21:36
General key info..:
pub rsa4096/109F2428DD97A597 2019-12-03 You McEngineer <you@example.com>
sec> rsa4096/109F2428DD97A597 created: 2019-12-03 expires: never
card-no: 0006 00015211
ssb> rsa4096/23DC6210FD32B9BF created: 2019-12-03 expires: never
card-no: 0006 00015211
ssb> rsa4096/C8219CCE0DABFC09 created: 2019-12-03 expires: never
card-no: 0006 00015211

导出你的 gpg 公钥,放在 GitHub,得让 GitHub 以后验证你的 commit 呀

gpg --armor --output you_pub.asc --export you@example.com

添加到 GitHub 就不多讲啦,跟 添加 ssh 密钥到 GitHub 是一样的。

设置 git commit (以后可以设置 tags)

查看密钥

> gpg --list-secret-keys --keyid-format LONG <youremail@example.com>

C:/Users/youruser/AppData/Roaming/gnupg/pubring.kbx
-----------------------------------------------
sec> rsa4096/36264D8005D951D8 2019-06-19 [SC]
12341C42734692704224266256EDCD8005D9ABD3
Card serial no. = 0006 12345678
uid [ultimate] Employee <employee@example.com>
ssb> rsa4096/B4E1273375AC2412 2019-06-19 [S] [expires: 2021-06-18]
ssb> rsa4096/2B5F29BB2DCA942D 2019-06-19 [E] [expires: 2021-06-18]
ssb> rsa4096/AC59547D0CCB5ACE 2019-06-19 [A] [expires: 2021-06-18]

配置 git

git config --global user.signingKey B4E1273375AC2412

为了避免以后每次 commit 都带有 -S ,可以这样配置

git config --global commit.gpgsign true

不过根据我的日常使用经验,每次隔一段时间,比如我隔一晚上,然后起来准备提交的时候。是需要先执行这个命令,然后输入 yubikey 的基本密码, 接下来所有的 commit 才是被 gpg verified 的状态!!!

为 macOS 添加制定的 GPG 执行程序

git config --global gpg.program gpg

给 commits 签名

输入下面的命令

git commit -S -m 'Fixed a small undocumented feature that made foo crash'

展示你上次签名过的 commit

git cat-file -p HEAD
tree c09dec94a1b2f8c4792fd0faef35623e0463fc73
parent 3fe8b3b4b9394678aeadfa4113e8982802f759f8
author Committer Name <committer@example.com> 1393232400 +0200
gpgsig -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAABCAAGBQJW/PEoAAoJEJDLBFvTmUcBo58H/1hb+uhqVCRRFnQDJ7gHM+v1
6vgWxtaEpf86foJe+V/8r2dij2fKAPcbMQbeakfO0PplSRUY6+XnvXY+2uFHs2TB
BxsAz1HYLnl6jXRKpLqduqJLmnwnkwaMCr1Bx/rZ1CWAsKtwBf4AGpW7ws9Dv6zh
Y7EPcVeO4dvftTqCsoOu6ZBmw9U24DA5XCl7ZG2nDiW9spS8CTlznGA3/LJ56mWF
Rm+xaJbfFwr2KS5wdyZkzdEh0sIcbmAYVhnKkj4HiBegrK+wCcayOfc0YMzOUPL9
uJ4pB32g0jLJbpNHRXqhQ/OU9eCRG3B55UBpimvLOLok3si6d/fYd3zTmB9bJaE=
=Bh19
-----END PGP SIGNATURE-----

验证你的 commits

命令显示你的 commit

$ git show HEAD --show-signature

commit 552b36ec86790bfdac679ab23e6d61133ff0b383
gpg: Signature made Sat 22 Feb 2014 11:00:00 CEST using RSA key ID AABBCCDD
gpg: Good signature from "Committer Name <committer@example.com>"
Author: Committer Name <committer@example.com>
Date: Sat Feb 22 11:00:00 2014 +0200

Fixed a small undocumented feature that made foo crash

GPG必须拥有签名者的公钥才能成功验证签名。

前面的命令假设感兴趣的提交是最后一次。要验证一个普通的提交,请将 HEAD 替换为提交 ID(本例中为 552b36ec86790bfdac679ab23e6d61133ff0b383)。

验证提交签名的替代命令是

git log --show-signature # Displays all commits and verify signed ones
git verify-commit HEAD # Displays and verify the latest commit

Conclusion

大概到现在,我们就已经全部完成了。就是这样!

· 4 min read
CheverJohn

I’m having trouble integrating openid-connect plugin with apisix gateway. When I have it enabled I end up getting no response from the API. Any idea what am I doing wrong or how to troubleshoot it? in slack

  1. enabled openid-connect plugin
curl [http://127.0.0.1:9080/apisix/admin/routes/5](http://127.0.0.1:9080/apisix/admin/routes/5) -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/get",
"plugins": {
"openid-connect": {
"client_id": "my-client",
"client_secret": "XXXX-XXXX-XXX",
"discovery": "[https://my-auth-server/myapi/.well-known/openid-configuration](https://my-auth-server/myapi/.well-known/openid-configuration)",
"access_token_in_authorization_header": true,
"bearer_only": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
  1. request to the /get endpoint results in Empty reply from server
curl -i -X GET [http://127.0.0.1:9080/get](http://127.0.0.1:9080/get) -H "Host: httpbin.org" -H "Authorization: Bearer #####token####"

curl: (52) Empty reply from server

3.   error.log has the following:

2022/03/18 21:23:09 [alert] 1#1: worker process 124 exited on signal 11
2022/03/18 21:23:09 [warn] 127#127: *723842 [lua] plugin.lua:172: load(): new plugins: {"uri-blocker":true,"fault-injection":true,"serverless-pre-function":true,"wolf-rbac":true,"datadog":true,"authz-keycloak":true,"skywalking-logger":true,"grpc-transcode":true,"splunk-hec-logging":true,"ext-plugin-pre-req":true,"ua-restriction":true,"ext-plugin-post-req":true,"response-rewrite":true,"key-auth":true,"grpc-web":true,"jwt-auth":true,"limit-count":true,"referer-restriction":true,"forward-auth":true,"udp-logger":true,"serverless-post-function":true,"basic-auth":true,"openwhisk":true,"cors":true,"limit-conn":true,"server-info":true,"azure-functions":true,"traffic-split":true,"request-validation":true,"google-cloud-logging":true,"rocketmq-logger":true,"sls-logger":true,"kafka-logger":true,"proxy-control":true,"proxy-rewrite":true,"syslog":true,"consumer-restriction":true,"echo":true,"http-logger":true,"prometheus":true,"redirect":true,"ip-restriction":true,"aws-lambda":true,"limit-req":true,"opa":true,"real-ip":true,"authz-casbin":true,"tcp-logger":true,"zipkin":true,"openid-connect":true,"gzip":true,"example-plugin":true,"request-id":true,"api-breaker":true,"hmac-auth":true,"ldap-auth":true,"proxy-mirror":true,"client-control":true,"proxy-cache":true}, context: init_worker_by_lua*
2022/03/18 21:23:09 [warn] 127#127: *723842 [lua] plugin.lua:222: load_stream(): new plugins: {"limit-conn":true,"ip-restriction":true,"mqtt-proxy":true}, context: init_worker_by_lua*

首先在我本地的 m1 上已安装的 APISIX 上看是否能重现bug。 流程如下:

  1. 进入 APISIX,使用 ./bin/apisix start 命令启动 APISIX。
  2. 直接报错 401,这个属于正常情况,因为没有做权限认证,就应该是这样的报错。

换一种重现方式:使用 docker 镜像(arm 版本) https://hub.docker.com/r/apache/apisix/tags#:~:text=3ab0b2f76959-,linux,-/arm64 首先复制命令

apache/apisix/2.12.1-alpine/images/sha256-3ab0b2f76959f057790b35adf2438fea5ae6cbc8c994aff159bf17d72654d857?context=explore
docker pull apache/apisix:2.12.1-alpine@sha256:3ab0b2f76959f057790b35adf2438fea5ae6cbc8c994aff159bf17d72654d857
docker pull nginx:stable-perl@sha256:3ab0b2f76959f057790b35adf2438fea5ae6cbc8c994aff159bf17d72654d857
docker pull nginx:stable-perl@sha256:3ab0b2f76959f057790b35adf2438fea5ae6cbc8c994aff159bf17d72654d857
docker run -itd --rm --name=dev-apisx -v /srv/[github.com/apache/apisix/conf/config.yaml:/usr/local/apisix/conf/config.yaml](http://github.com/apache/apisix/conf/config.yaml:/usr/local/apisix/conf/config.yaml) apache/apisix

修改:docker tag c8202912bb3a apache/apisix:dev 这个命令用于运行apisix,记住这边得先把 APISIX镜像的tag改了哈改成 apache/apisix:dev

docker run -itd --rm --name=dev-apisx -p 9080:9080 -v /Users/cheverjohn/home/api7/dev_cj/apisix/conf/config.yaml:/usr/local/apisix/conf/config.yaml apache/apisix:dev

上面的这条命令要好好理解,这是最终的状态。

![[dockerdestop.png]]

这边还有一个 etcd 的映射端口更改。

这一块需要思考到的地方有, etcd 由于我是本地使用 brew 命令安装的,所以它会默认由brew 守护开启,也就是无论你开关机它都会启动。这个 需要额外关闭。我是通过这条命令看到的

brew info etcd

看到可以这样关闭 etcd

brew services stop etcd
ETCD_UNSUPPORTED_ARCH="arm64" /opt/homebrew/opt/etcd/bin/etcd
ETCD_UNSUPPORTED_ARCH="arm64" /opt/homebrew/opt/etcd/bin/etcd --listen-client-urls=http://0.0.0.0:2379
ETCD_UNSUPPORTED_ARCH="arm64" /opt/homebrew/opt/etcd/bin/etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2379 --listen-peer-urls http://0.0.0.0:2380 --initial-advertise-peer-urls http://0.0.0.0:2380

其中为了确认 etcd 的安装位置,他的端口状态,会一直使用到以下命令:

lsof -i:2379

得出运行 2379 端口的进程。

lsof -p PID

根据 PID 得到进程的具体位置,根据这个操作确认到 进程的具体位置。

这里边超哥贡献了一些命令:

history | grep etcd
curl http://192.168.28.179:2379/version

期望通过这个配置,判断是否正常启动好 etcd。

还有命令:

docker logs aae1b3434ce4

这里边的 后边的数字其实是 container ID

此处码一下,希望了解清楚以下两条命令的区别:

docker ps

docker ps -a

下面的代码也要了解清楚各种参数的意思:

docker run -itd --name=dev-apisx -v /Users/cheverjohn/home/api7/dev_cj/apisix/conf/config.yaml:/usr/local/apisix/conf/config.yaml apache/apisix:dev

查看日志命令

tail -f error.log

有时候我也看到会连续执行两条命令:

docker stop 9b17b3bbb061

docker rm 9b17b3bbb061

docker rmi c8202912bb3a

检查: docker inspect apache/apisix:dev

这边配置好 etcd 和 APISIX 之后,开始 curl 请求 ifconfig | grep 192.168 找到了:curl http://192.168.101.161:2379/version

· 3 min read
CheverJohn

首先上我最终跑通一个测试的例子:

Installation

按照正常的操作,我先 clone fork 下来的仓库,然后安装相关依赖,这个我还是根据了 APISIX 2.10 的文档版本 里讲一系列步骤做的。千万注意,这个方法已经老套了,你应该用下面介绍的最新脚本的方法,如图所示:

ubuntu 安装依赖

Make deps

然后这个地方坑的就来了,在最新的github 脚本里边,是有下面的这行命令的,也就是文档内容跟最新脚本内容是不相符的。 这个需要我及时去进行修改。

sudo apt-get install -y git openresty curl openresty-openssl111-dev make gcc libpcre3 libpcre3-dev libldap2-dev unzip

事实上运行了上面的命令之后,就不会有什么找不到 ldap 之类的问题了,淦

然后我们解决了 make deps 的问题。接下来就直接是 make install,一切正常。

开始测试部分

首先根据官方的命令安装

  1. 第一是安装 perl 的包管理工具 cpanminus
apt install cpanminus
  1. 第二然后通过 cpanm 安装 test-nginx 的依赖。
sudo cpanm --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1)
  1. 首先将 APISIX 加入到框架中去
export PERL5LIB=.:$PERL5LIB:/home/api7/dev_cj/apisix
  1. 然后配置OpenResty 中的 NGINX 的环境变量配置
export PATH=/usr/local/openresty/nginx/sbin:$PATH

如果你遇到这样的问题

你就需要下载子模块:

git submodule update --init --recursive

请注意,当我仅运行

apisix start

and

nohup etcd &

之后,便能够成功运行,如图

虚拟机经历了很多 虚拟机经历了很多

· 5 min read
CheverJohn

本来是不打算写得,可是今天在写一个本周五分享会主题的时候,一不小心写嗨了,就多了很多字,又不舍得删掉,就放我博客叭就。

前言

大家好,首先肯定得自我介绍一下,我是编码练习三年半的 JUST 应届毕业老学长 CheverJohn,虽然按照实打实算,我只是在18年秋天步入软件工程的课堂才算是入了门,但是我自以为三年半个年头里,学习的路线并没有太大问题,甚至可能自诩有一个还不错的规划?!目前个人最为感兴趣的一块就是编译原理、以及各种编程语言的实现这一块,毕竟学习各种编程语言的艺术看,多是一件美事。

对了,再简要讲一下目前为止个人的“主要社会价值”叭:

  1. 大一刚开始那会儿用 cpp 写了个密码小软件,至今还用着(至少我换 m1 之前还在用),
  2. 然后也搞过树莓派做机器学习,在大家都用树莓派做垃圾处理的时候,去做了天气识别预报(巨坑),
  3. 接下来搞了企业级开发,误入 Django 邪教,开发了社区博客系统(可以多人运动的那种),目前已经挂了,不过我将项目捐给了我校网协 github 组织,希望学弟学妹们能用上。
  4. 从 Django 拐出来后呢,开始学习 Java 的 Spring 全家桶,使用 ruoyi 框架实现了一次分布式(在我破笔电上丧心病狂放了三个虚拟机同时跑后端)。然后又跟三个好基友们组队纯手工完成一个综合管理系统,可惜后来人菜瘾大,想搞很多东西,但又都没有时间,结果夭折了,唉。不过我从中抽离出一个开源项目,前几天还有人 fork 并 star 呢,开心ing!虽然目前也就只有 6 个 star。
  5. 接下来就来到了我的大三,参与了社区(咋感觉就跟入了贼船一样),第一个加入的是 vscode 中文社区,担任过几次社区月会主持人,线下核心志愿者,然后就无了,或许还写过几个没人用的 vscode 插件,谁知道呢又。
  6. 与开始备战考研的同学不一样,我又开始了一次 OSPP,有幸加入 tuna 开源组织,并贡献了三个项目的代码重构工作,认识到很多很厉害的人。
  7. 目前专心于 Apache 各个开源项目,以及我 tuna 社区的 nfcim 项目里。坚信 flutter 是未来移动端的希望。 糟糕啊,一下子写多了,不过希望能帮助到学弟学妹们哈。

扯远了,回归主题

做啥事都应该有目的的,我一直都这样认为,所以我经常被称为目的性,但为了自己的兴趣爱好具备点目的性,我觉得不是一件坏事。 本次活动的主旨是 git 的日常使用、GitHub 的日常使用、开源社区的参与&贡献

另:女生节快乐哈!

· 10 min read
CheverJohn

本文由 简悦 SimpRead 转码, 原文地址 www.cnblogs.com

Linux 环境变量配置

在自定义安装软件的时候,经常需要配置环境变量,下面列举出各种对环境变量的配置方法。

下面所有例子的环境说明如下:

  • 系统:Ubuntu 14.0
  • 用户名:uusama
  • 需要配置 MySQL 环境变量路径:/home/uusama/mysql/bin

Linux 读取环境变量

读取环境变量的方法:

  • export命令显示当前系统定义的所有环境变量
  • echo $PATH命令输出当前的PATH环境变量的值

这两个命令执行的效果如下

uusama@ubuntu:~$ export
declare -x HOME="/home/uusama"
declare -x LANG="en_US.UTF-8"
declare -x LANGUAGE="en_US:"
declare -x LESSCLOSE="/usr/bin/lesspipe %s %s"
declare -x LESSOPEN="| /usr/bin/lesspipe %s"
declare -x LOG
declare -x MAIL="/var/mail/uusama"
declare -x PATH="/home/uusama/bin:/home/uusama/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
declare -x SSH_TTY="/dev/pts/0"
declare -x TERM="xterm"
declare -x USER="uusama"

uusama@ubuntu:~$ echo $PATH
/home/uusama/bin:/home/uusama/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

其中PATH变量定义了运行命令的查找路径,以冒号:分割不同的路径,使用export定义的时候可加双引号也可不加。

Linux 环境变量配置方法一:export PATH

使用export命令直接修改PATH的值,配置 MySQL 进入环境变量的方法:

export PATH=/home/uusama/mysql/bin:$PATH

# 或者把PATH放在前面
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

  • 生效时间:立即生效
  • 生效期限:当前终端有效,窗口关闭后无效
  • 生效范围:仅对当前用户有效
  • 配置的环境变量中不要忘了加上原来的配置,即$PATH部分,避免覆盖原来配置

Linux 环境变量配置方法二:vim ~/.bashrc

通过修改用户目录下的~/.bashrc文件进行配置:

vim ~/.bashrc

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

  • 生效时间:使用相同的用户打开新的终端时生效,或者手动source ~/.bashrc生效
  • 生效期限:永久有效
  • 生效范围:仅对当前用户有效
  • 如果有后续的环境变量加载文件覆盖了PATH定义,则可能不生效

Linux 环境变量配置方法三:vim ~/.bash_profile

和修改~/.bashrc文件类似,也是要在文件最后加上新的路径即可:

vim ~/.bash_profile

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

  • 生效时间:使用相同的用户打开新的终端时生效,或者手动source ~/.bash_profile生效
  • 生效期限:永久有效
  • 生效范围:仅对当前用户有效
  • 如果没有~/.bash_profile文件,则可以编辑~/.profile文件或者新建一个

Linux 环境变量配置方法四:vim /etc/bashrc

该方法是修改系统配置,需要管理员权限(如 root)或者对该文件的写入权限:

# 如果/etc/bashrc文件不可编辑,需要修改为可编辑
chmod -v u+w /etc/bashrc

vim /etc/bashrc

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

  • 生效时间:新开终端生效,或者手动source /etc/bashrc生效
  • 生效期限:永久有效
  • 生效范围:对所有用户有效

Linux 环境变量配置方法五:vim /etc/profile

该方法修改系统配置,需要管理员权限或者对该文件的写入权限,和vim /etc/bashrc类似:

# 如果/etc/profile文件不可编辑,需要修改为可编辑
chmod -v u+w /etc/profile

vim /etc/profile

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

  • 生效时间:新开终端生效,或者手动source /etc/profile生效
  • 生效期限:永久有效
  • 生效范围:对所有用户有效

Linux 环境变量配置方法六:vim /etc/environment

该方法是修改系统环境配置文件,需要管理员权限或者对该文件的写入权限:

# 如果/etc/bashrc文件不可编辑,需要修改为可编辑
chmod -v u+w /etc/environment

vim /etc/profile

# 在最后一行加上
export PATH=$PATH:/home/uusama/mysql/bin

注意事项:

  • 生效时间:新开终端生效,或者手动source /etc/environment生效
  • 生效期限:永久有效
  • 生效范围:对所有用户有效

Linux 环境变量加载原理解析

上面列出了环境变量的各种配置方法,那么 Linux 是如何加载这些配置的呢?是以什么样的顺序加载的呢?

特定的加载顺序会导致相同名称的环境变量定义被覆盖或者不生效。

环境变量的分类

环境变量可以简单的分成用户自定义的环境变量以及系统级别的环境变量。

  • 用户级别环境变量定义文件:~/.bashrc~/.profile(部分系统为:~/.bash_profile
  • 系统级别环境变量定义文件:/etc/bashrc/etc/profile(部分系统为:/etc/bash_profile)、/etc/environment

另外在用户环境变量中,系统会首先读取~/.bash_profile(或者~/.profile)文件,如果没有该文件则读取~/.bash_login,根据这些文件中内容再去读取~/.bashrc

测试 Linux 环境变量加载顺序的方法

为了测试各个不同文件的环境变量加载顺序,我们在每个环境变量定义文件中的第一行都定义相同的环境变量UU_ORDER,该变量的值为本身的值连接上当前文件名称。

需要修改的文件如下:

  • /etc/environment
  • /etc/profile
  • /etc/profile.d/test.sh,新建文件,没有文件夹可略过
  • /etc/bashrc,或者/etc/bash.bashrc
  • ~/.bash_profile,或者~/.profile
  • ~/.bashrc

在每个文件中的第一行都加上下面这句代码,并相应的把冒号后的内容修改为当前文件的绝对文件名。

export UU_ORDER="$UU_ORDER:~/.bash_profile"

修改完之后保存,新开一个窗口,然后echo $UU_ORDER观察变量的值:

uusama@ubuntu:~$ echo $UU_ORDER
$UU_ORDER:/etc/environment:/etc/profile:/etc/bash.bashrc:/etc/profile.d/test.sh:~/.profile:~/.bashrc

可以推测出 Linux 加载环境变量的顺序如下:

  1. /etc/environment
  2. /etc/profile
  3. /etc/bash.bashrc
  4. /etc/profile.d/test.sh
  5. ~/.profile
  6. ~/.bashrc

Linux 环境变量文件加载详解

由上面的测试可容易得出 Linux 加载环境变量的顺序如下,:

系统环境变量 -> 用户自定义环境变量
/etc/environment -> /etc/profile -> ~/.profile

打开/etc/profile文件你会发现,该文件的代码中会加载/etc/bash.bashrc文件,然后检查/etc/profile.d/目录下的.sh文件并加载。

# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).

if [ "$PS1" ]; then
if [ "$BASH" ] && [ "$BASH" != "/bin/sh" ]; then
# The file bash.bashrc already sets the default PS1.
# PS1='\h:\w\$ '
if [ -f /etc/bash.bashrc ]; then
. /etc/bash.bashrc
fi
else
if [ "`id -u`" -eq 0 ]; then
PS1='# '
else
PS1='$ '
fi
fi
fi

if [ -d /etc/profile.d ]; then
for i in /etc/profile.d/*.sh; do
if [ -r $i ]; then
. $i
fi
done
unset i
fi

其次再打开~/.profile文件,会发现该文件中加载了~/.bashrc文件。

# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi

# set PATH so it includes user's private bin directories
PATH="$HOME/bin:$HOME/.local/bin:$PATH"

~/.profile文件中代码不难发现,/.profile文件只在用户登录的时候读取一次,而/.bashrc会在每次运行Shell脚本的时候读取一次。

一些小技巧

可以自定义一个环境变量文件,比如在某个项目下定义uusama.profile,在这个文件中使用export定义一系列变量,然后在~/.profile文件后面加上:sourc uusama.profile,这样你每次登陆都可以在 Shell 脚本中使用自己定义的一系列变量。

也可以使用alias命令定义一些命令的别名,比如alias rm="rm -i"(双引号必须),并把这个代码加入到~/.profile中,这样你每次使用rm命令的时候,都相当于使用rm -i命令,非常方便。

· One min read
CheverJohn

由于一些原因,我在思考本博客网站的内容。或许接下来一段时间我会好好整理内容。

· 3 min read
CheverJohn

要去深圳了今天,期待明天的深圳初见!

飞机之旅

离开南通

离开南通

感受到飞机的推背感

感受到飞机的推背感

飞机冲上第一个云层

飞机冲上第一个云层

飞机冲上第二个云层

飞机冲上第二个云层

吃飞机餐

吃飞机餐

飞机冲上第三个云层

飞机冲上第三个云层

飞机在第三个云层

抵达深圳宝安机场

抵达深圳宝安机场

抵达深圳宝安机场2

找房子的过程中远眺我司

找房子的过程中远眺我司

下一站翻身

下一站翻身

小广告不能信

小广告不能信

空中快乐小屋

空中快乐小屋1 空中快乐小屋2

广州早茶

广州早茶 广州早茶2

我司楼下小企鹅

小企鹅

租房的问题

以后再说,这里面太难了!