在实际工作中,通过prometheus监控的主要对象有如下几个:

  • 基础设施层:主要是监控k8s节点资源,如CPU,内存,网络吞吐和带宽占用,磁盘I/O和磁盘使用等指标;
  • 中间件层:监控产品使用到的中间件(一般会独立部署在外部集群),主要有consul、mysql、nats、redis、haproxy
  • Kubernetes集群:监控Kubernetes集群本身的关键指标
  • Kubernetes集群上部署的应用:监控部署在Kubernetes集群上的应用(pod或container等)

Step By Step,部署工作正式开始!

环境介绍

操作系统环境:centos linux 7.4 64bit

K8S软件版本: v1.8.6

Master节点IP: 192.168.1.111/24

Node节点IP: 192.168.1.155/24 192.168.1.251/24

采用daemonset方式部署node-exporter组件

部署node-exporter.yaml文件

节点上默认暴露9100端口,通过hostip:9100即可访问node-exporter的metrics

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# cat node-exporter.yaml
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: node-exporter
name: node-exporter
name: node-exporter
namespace: kube-system
annotations:
prometheus.io/scrape: 'true'
spec:
ports:
- name: http
port: 9100
protocol: TCP
selector:
app: node-exporter
type: ClusterIP
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: node-exporter
namespace: kube-system
labels:
app: node-exporter
spec:
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true
containers:
- image: prom/node-exporter:v0.16.0
imagePullPolicy: IfNotPresent
name: node-exporter
ports:
- containerPort: 9100
hostPort: 9100
name: http
volumeMounts:
- name: local-timezone
mountPath: "/etc/localtime"
tolerations:
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
hostPID: true
restartPolicy: Always
volumes:
- name: local-timezone
hostPath:
path: /etc/localtime

部署成功截图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@test--0005 liaoxb]# kubectl create -f node-exporter.yaml
service "node-exporter" created
daemonset "node-exporter" created
[root@test--0005 liaoxb]# kcs get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kube-apiserver-test--0005 1/1 Running 0 5d 192.168.1.111 test--0005
kube-controller-manager-test--0005 1/1 Running 0 5d 192.168.1.111 test--0005
kube-dns-5cfc95db9f-qxk55 3/3 Running 0 5d 10.244.0.62 test--0005
kube-flannel-ds-48xfp 1/1 Running 0 5d 192.168.1.155 test--0006
kube-flannel-ds-d84t5 1/1 Running 0 5d 192.168.1.251 test--0007
kube-flannel-ds-nm8xl 1/1 Running 0 5d 192.168.1.111 test--0005
kube-proxy-dxxd7 1/1 Running 0 5d 192.168.1.155 test--0006
kube-proxy-hfzlf 1/1 Running 0 5d 192.168.1.251 test--0007
kube-proxy-zw8qr 1/1 Running 0 5d 192.168.1.111 test--0005
kube-scheduler-test--0005 1/1 Running 0 5d 192.168.1.111 test--0005
kubernetes-dashboard-d8b49876-2l2gx 1/1 Running 0 5d 10.244.0.63 test--0005
node-exporter-dzsq7 1/1 Running 0 46s 192.168.1.155 test--0006
node-exporter-mkxrd 1/1 Running 0 46s 192.168.1.111 test--0005
node-exporter-s8xw2 1/1 Running 0 46s 192.168.1.251 test--0007
tiller-69ccbb4f7f-6dbsg 1/1 Running 0 4d 192.168.1.155 test--0006
[root@test--0005 liaoxb]# kcs get svc -o wide |grep node-exporter
node-exporter ClusterIP 10.105.53.97 <none> 9100/TCP 1m app=node-exporter

部署prometheus组件

部署rbac文件

prometheus-rbac.yml定义了Prometheus容器访问k8s apiserver所需的ServiceAccount和ClusterRole及ClusterRoleBinding

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# cat prometheus-rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups: [""]
resources:
- nodes
- nodes/proxy
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups:
- extensions
resources:
- ingresses
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus
subjects:
- kind: ServiceAccount
name: prometheus
namespace: kube-system

部署prometheus的配置文件configmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#cat prometheus-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: kube-system
data:
prometheus.yml: |
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:

- job_name: 'kubernetes-apiservers-567'
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
action: keep
regex: default;kubernetes;https

- job_name: 'kubernetes-cadvisor-567'
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor

- job_name: 'kubernetes-nodes-567'
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: kubernetes_name

部署Prometheus deployment 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# cat prometheus-deploy.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
labels:
name: prometheus-deployment
name: prometheus
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: prometheus
template:
metadata:
labels:
app: prometheus
spec:
containers:
- image: prom/prometheus:v2.7.1
name: prometheus
command:
- "/bin/prometheus"
args:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention=24h"
ports:
- containerPort: 9090
protocol: TCP
volumeMounts:
- mountPath: "/prometheus"
name: data
- mountPath: "/etc/prometheus"
name: config-volume
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 500m
memory: 2500Mi
serviceAccountName: prometheus
imagePullSecrets:
- name: regsecret
volumes:
- name: data
hostPath:
path: /prometheus
- name: config-volume
configMap:
name: prometheus-config

部署Prometheus svc 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#cat prometheus-svc.yaml
kind: Service
apiVersion: v1
metadata:
labels:
app: prometheus
name: prometheus
namespace: kube-system
spec:
type: NodePort
ports:
- port: 9090
targetPort: 9090
nodePort: 32002
selector:
app: prometheus

部署成功截图:

1
2
3
4
5
6
7
8
9
10
11
12
[root@test--0005 liaoxb]# kubectl create -f prometheus-rbac.yaml
clusterrole "prometheus" created
serviceaccount "prometheus" created
clusterrolebinding "prometheus" created
[root@test--0005 liaoxb]# kubectl create -f prometheus-cm.yaml
configmap "prometheus-config" created
[root@test--0005 liaoxb]# kubectl create -f prometheus-deploy.yaml
deployment "prometheus" created
[root@test--0005 liaoxb]# kubectl create -f prometheus-svc.yaml
service "prometheus" created
[root@test--0005 liaoxb]# kcs get pods -o wide |grep prometheus
prometheus-78c8788f44-cmt9g 1/1 Running 0 32s 10.244.2.32 test--0007

通过prometheus节点加上nodeport即可访问prometheus web页面,target页面可看见prometheus已经成功连接上监控的job;此时prometheus就可以拉取并存储每个job采集的时序数据,Graph界面上提供了基本的查询K8S集群中每个POD的CPU使用情况,PromQL查询条件如下:

1
sum by (pod_name)( rate(container_cpu_usage_seconds_total{image!="", pod_name!=""}[1m] ) )

prometheus节点ip:32002访问prometheus ui

PromQL查询数据

部署Grafana组件

部署grafana.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#cat grafana.yaml
apiVersion: v1
kind: Service
metadata:
name: grafana
namespace: kube-system
spec:
type: NodePort
ports:
- port: 3000
targetPort: 3000
nodePort: 32003
selector:
app: grafana
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: grafana
name: grafana
namespace: kube-system
spec:
replicas: 1
revisionHistoryLimit: 2
template:
metadata:
labels:
app: grafana
spec:
containers:
- image: grafana/grafana:4.2.0
name: grafana
imagePullPolicy: Always
ports:
- containerPort: 3000
env:
- name: GF_AUTH_BASIC_ENABLED
value: "true"
- name: GF_AUTH_ANONYMOUS_ENABLED
value: "false"
[root@test--0005 liaoxb]# kubectl create -f grafana.yaml
service "grafana" created
deployment "grafana" created
[root@test--0005 liaoxb]# kcs get pods -o wide |grep grafana
grafana-f9f5975f8-mv74b 1/1 Running 0 24s 10.244.1.32 test--0006
[root@test--0005 liaoxb]# kcs get svc -o wide |grep grafana
grafana NodePort 10.102.160.34 <none> 3000:32003/TCP 42s app=grafana

此时就可以通过grafana节点ip:32003访问grafana web页面,账户密码默认都是admin;

grafana配置数据源为prometheus

导入监控Dashboard

使用Kubernetes cluster monitoring (via Prometheus)这个即可

Dashboard数据展示

主机监控数据展示

pod和container数据展示

Kubernetes集群上部署应用的监控

Kubernetes集群上Pod, DaemonSet, Deployment, Job, CronJob等各种资源对象的状态需要监控,这也反映了使用这些资源部署的应用的状态。但通过查看前面Prometheus从k8s集群拉取的指标(这些指标主要来自apiserver和kubelet中集成的cAdvisor),并没有具体的各种资源对象的状态指标。对于Prometheus来说,当然是需要引入新的exporter来暴露这些指标,Kubernetes提供了一个kube-state-metrics正式我们需要。

在Kubernetes上部署kube-state-metrics组件

https://github.com/kubernetes/kube-state-metrics.git

kube-state-metrics/kubernetes目录下,有所需要的文件

1
2
3
4
5
6
7
8
[root@test--0005 liaoxb]# kubectl create -f kube-state-metrics/kubernetes/
clusterrolebinding "kube-state-metrics" created
clusterrole "kube-state-metrics" created
deployment "kube-state-metrics" created
rolebinding "kube-state-metrics" created
role "kube-state-metrics-resizer" created
serviceaccount "kube-state-metrics" created
service "kube-state-metrics" created

将kube-state-metrics部署到Kubernetes上之后,就会发现Kubernetes集群中的Prometheus会在kubernetes-nodes-567这个job下自动服务发现kube-state-metrics,并开始拉取metrics。这是因为prometheus-cm.yml中Prometheus的配置文件job kubernetes-nodes-567的配置。而部署kube-state-metrics的定义文件kube-state-metrics-service.yaml对kube-state-metrics Service的定义包含annotation prometheus.io/scrape: ‘true’,因此kube-state-metrics的endpoint可以被Prometheus自动服务发现

查询k8s集群中deploy的个数:

中间件监控

关于中间件的exporter部署请自行在prometheus项目中查找
https://github.com/prometheus
最主要的关键点是配置好prometheus.yml文件,在configmap中追加如下格式内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
- job_name: consul
scrape_interval: 30s
scrape_timeout: 30s
metrics_path: /metrics
scheme: http
static_configs:
- targets:
- 192.168.1.111:9107
- 192.168.1.155:9107
- 192.168.1.251:9107
- job_name: haproxy
scrape_interval: 30s
scrape_timeout: 30s
metrics_path: /metrics
scheme: http
static_configs:
- targets:
- 192.168.1.111:9101
- job_name: mysql
scrape_interval: 30s
scrape_timeout: 30s
metrics_path: /metrics
scheme: http
static_configs:
- targets:
- 192.168.1.111:9104
- 192.168.1.155:9104
- 192.168.1.251:9104
- job_name: nats
scrape_interval: 30s
scrape_timeout: 30s
metrics_path: /metrics
scheme: http
static_configs:
- targets:
- 192.168.1.111:7777
- 192.168.1.155:7777
- 192.168.1.251:7777
- job_name: redis
scrape_interval: 30s
scrape_timeout: 30s
metrics_path: /metrics
scheme: http
static_configs:
- targets:
- 192.168.1.155:9121

prometheus-cm.yaml里job追加配置成功后,需要kubectl apply -f prometheus-cm.yaml,并且重启prometheus实例;重启成功后在target页面就可以看见新增加的中间件job采集项。

consul haproxy等中间件采集job

部署实践小结:

  • 至此,我们就能通过grafana能够展示基础设施层、Kubernetes集群自身的监控数据指标,比如cpu、内存、网络IO等(数据采集组件分别是node-exporter、cadvisor)
  • Kubernetes集群上部署应用的监控,尤其是对应用状态的监控,主要是采用kube-state-metrics组件的指标,这是对以上组件很好的补充
  • 中间件监控,主要是部署各自的exporter容器,暴露固定端口以供prometheus拉取监控metrics数据

参考链接:

https://www.kubernetes.org.cn/3418.html

https://github.com/prometheus

需求背景

1、测试环境部署了一套监控系统,测试人员经常需要访问web去分析数据或定位问题,但是访问不方便也不灵活,每次需要去找到pod运行主机IP和svc暴露的端口。
2、通过利用nginx反向代理+负载均衡配置,快速地访问系统。比如prometheus、granfana等

配置步骤

1、查看测试集群监控服务的pod和svc信息,prometheus和grafana均以NodePort的形式映射到主机端口。

1
2
3
4
5
6
7
8
|kubernetes-admin@q4-default# kcc get po,svc |grep grafana
pod/grafana-6c5f687b5b-79qf8 1/1 Running 0 56m

service/grafana NodePort 10.104.106.121 <none> 3000:31962/TCP 12d
|kubernetes-admin@q4-default# kca get po,svc |grep prometheus
pod/prometheus-68d7459bb-cmnmn 5/5 Running 0 2d

service/prometheus NodePort 10.99.169.156 <none> 81:32001/TCP,9093:32003/TCP 2d

这时是可以通过集群内主机内网ip+端口,成功访问到监控系统。比如访问prometheus端口32001

1
2
3
4
5
6
7
8
[root@harbor nginx-proxy]# curl 192.168.0.34:32001
<a href="/graph">Found</a>.

[root@harbor nginx-proxy]# curl 192.168.0.35:32001
<a href="/graph">Found</a>.

[root@harbor nginx-proxy]# curl 192.168.0.36:32001
<a href="/graph">Found</a>.

2、nginx配置文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[root@harbor nginx-proxy]# cat default.conf
# 设定实际的后端服务器列表
upstream prometheus_server{
#设定负载均衡的服务器列表,weigth参数表示权值(缺省是1),权值越高被分配到的几率越大
server 192.168.0.34:32001 weight=1;
server 192.168.0.35:32001 weight=2;
server 192.168.0.36:32001 weight=3;
}

upstream alert_server{
server 192.168.0.34:32003;
server 192.168.0.35:32003;
server 192.168.0.36:32003;
}
upstream grafana_server{
server 192.168.0.34:31962;
#server 192.168.0.35:31962;
#server 192.168.0.36:31962;
}


server {
#监听80端口,用于HTTP协议
listen 80;
#定义使用www.test.com访问
server_name www.test.com;
proxy_headers_hash_max_size 51200;
proxy_headers_hash_bucket_size 6400;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

#location / {
# root /usr/share/nginx/html;
# index index.html;
#}
#反向代理的路径
location / {
#请求将转向upstream里prometheus_server定义的服务器列表
proxy_pass http://prometheus_server/;
#nginx跟后端服务器连接超时时间(代理连接超时)
proxy_connect_timeout 30s;
}
location /alert/ {
proxy_pass http://alert_server/;
proxy_connect_timeout 30s;
}
location /grafana/ {
proxy_pass http://grafana_server/;
proxy_connect_timeout 30s;
}
}

3、make run快速启动nginx容器
Makefile里总共三步操作:
快速启动nginx容器,映射到主机端口8081,
拷贝default.conf到nginx容器/etc/nginx/conf.d/目录
重启nginx容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@harbor nginx-proxy]# ll
总用量 12
-rw-r--r-- 1 root root 1587 1月 24 21:39 default_backup.conf
-rw-r--r-- 1 root root 1327 1月 24 21:40 default.conf
-rw-r--r-- 1 root root 353 1月 24 21:44 Makefile
[root@harbor nginx-proxy]# make run
docker rm -f nginx-web
nginx-web
docker run -d -p 8081:80 --name nginx-web nginx
229484284a78d84800527337eb7a074d42ff62987cb8e479a0d6c4c65b586156
docker cp default.conf nginx-web:/etc/nginx/conf.d/
docker restart nginx-web
nginx-web
[root@harbor nginx-proxy]# docker ps |grep nginx-web
229484284a78 nginx "nginx -g 'daemon ..." 30 seconds ago Up 29 seconds 0.0.0.0:8081->80/tcp nginx-web

4、在浏览器中访问 www.test.com,这时应该就可以根据location,访问到不同的服务了。
访问Grafana Dashboard:

访问Alertmanager ui:

访问:Prometheus ui

关于负载均衡策略

Nginx提供了多种负载均衡策略,在上面其实已用到过轮询算法。在这里延伸多了解一下其它策略。

轮询

1
2
3
4
5
6
upstream bck_testing_01 {
# 默认所有服务器权重为 1
server 192.168.250.220:8080
server 192.168.250.221:8080
server 192.168.250.222:8080
}

加权轮询

1
2
3
4
5
upstream bck_testing_01 {
server 192.168.250.220:8080 weight=3
server 192.168.250.221:8080
server 192.168.250.222:8080
}

最少连接

1
2
3
4
5
6
upstream bck_testing_01 {
least_conn;
server 192.168.250.220:8080
server 192.168.250.221:8080
server 192.168.250.222:8080
}

IP Hash

1
2
3
4
5
6
upstream bck_testing_01 {
ip_hash;
server 192.168.250.220:8080
server 192.168.250.221:8080
server 192.168.250.222:8080
}

参考文档:
https://www.w3cschool.cn/nginx/nginx-d1aw28wa.html
https://mp.weixin.qq.com/s/qMtJtZ6g62wibRVilIHPNg

上次了解到nginx相关基础知识,这次就趁热打铁,学习亲手搭建一个静态资源的文件服务器。其中会涉及到gzip功能的配置。

搭建目标

1、可以成功访问一些静态资源文件(图片、日志文件html等)
2、服务器会以gzip压缩的形式返回数据

搭建步骤

容器运行nginx,端口映射到本机8080

查看静态资源文件和nginx.conf

本地机器上,静态资源全部放在static-web目录下。
子目录img存放的是图片jpg、png,子目录robot-log存放的是每天归档的测试日志报告html。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
localhost:nginx-test liaoxb$ tree
.
├── nginx.conf
└── static-web
├── img
│ ├── test01.jpg
│ └── test02.png
└── robot-log
├── 2019-01-16
│ ├── log.html
│ ├── output.xml
│ └── report.html
└── 2019-01-17
├── log.html
├── output.xml
└── report.html

相比nginx容器内的默认配置文件,本地对nginx.conf做了如下改动(重要):
1、开启了gzip功能,并配置了相关参数(后面会详细介绍参数)
2、server块里追加了两个location块(/img/、/robot-log/),将对应请求路由到root所指向的目录或index文件
3、修改了server_name,记得在本地主机/etc/hosts文件下写入static.web.com
4、注释了include参数,不过根目录依然是可以访问到nginx默认欢迎页面的。

完整配置内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
user  nginx;
worker_processes 1;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;


events {
worker_connections 1024;
}


http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 3;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript image/jpeg image/jpg image/png;
gzip_proxied any;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";


server {
listen 80;
server_name static.web.com;

location / {
root /usr/share/nginx/html;
index index.html;
}
location /img/ {
root /usr/share/static-web;
autoindex on;
}
location /robot-log/ {
root /usr/share/static-web;
autoindex on;
}
}

#include /etc/nginx/conf.d/*.conf;
}

动态配置nginx容器

动态配置nginx容器,需执行以下三步操作:
1、替换容器内的/etc/nginx/nginx.conf
2、拷贝静态资源目录static-web到指定的容器目录/usr/share/
3、重启nginx容器

1
2
3
4
5
6
7
8
9
10
11
12
13
localhost:nginx-test liaoxb$ ll
total 8
drwxr-xr-x 4 liaoxb staff 128 3 2 22:56 ./
drwxr-xr-x 10 liaoxb staff 320 3 1 23:28 ../
-rw-r--r--@ 1 liaoxb staff 1404 1 16 2019 nginx.conf
drwxr-xr-x 5 liaoxb staff 160 1 16 2019 static-web/
localhost:nginx-test liaoxb$ docker cp nginx.conf nginx-test:/etc/nginx/
localhost:nginx-test liaoxb$ docker cp static-web nginx-test:/usr/share/
localhost:nginx-test liaoxb$ docker restart nginx-test
nginx-test
localhost:nginx-test liaoxb$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
addfae34988b nginx "nginx -g 'daemon of…" About an hour ago Up 7 seconds 0.0.0.0:8080->80/tcp nginx-test

访问静态资源

1、域名:8080访问根目录,成功访问nginx默认web页面

2、域名:8080访问/img/,成功访问目录下的所有图片

3、域名:8080访问/robot-log/,成功访问目录下的归档日志

gzip配置详解

Nginx实现资源压缩的原理是通过ngx_http_gzip_module模块拦截请求,并对需要做gzip的类型做gzip,ngx_http_gzip_module是Nginx默认集成的,不需要重新编译,直接开启即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 开启gzip
gzip on;
# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;
# 设置压缩所需要的缓冲区大小
gzip_buffers 4 16k;
# 设置gzip压缩针对的HTTP协议版本
gzip_http_version 1.1;
# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 3;
# 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript image/jpeg image/jpg image/png;
gzip_proxied any;
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
# 禁用IE 6 gzip
gzip_disable "MSIE [1-6]\.";

压缩效果对比

curl命令直接对比查看:

第一次curl请求头未带’Accept-Encoding: gzip,deflate’时,服务器不会压缩,直接返回html,从Content-Length也可以看出report.html的size是233340,也就是228kb大小。

第二次curl请求头带了’Accept-Encoding: gzip,deflate’时,服务器则会进行压缩数据后再返回content,同时response字段也会出现Content-Encoding: gzip,这就证明gzip压缩配置生效了。不过这次的response看不见Content-Length,怎么确定压缩成多少了呢?

这也很容易,结合着浏览器访问同个web页面查看size就清楚了,压缩后是77.1kb。

参考文档:
https://www.w3cschool.cn/nginx/nginx-d1aw28wa.html

Nginx常用功能

http正向代理

正向代理是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
当然前提是客户端要知道正向代理服务器的 IP 地址,还有代理程序的端口。

正向代理的用途:
(1)访问原来无法访问的资源,如google
(2) 可以做缓存,加速访问资源
(3)对客户端访问授权,上网进行认证
(4)代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息

反向代理

反向代理(Reverse Proxy)实际运行方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
反向代理的作用:
(1)保证内网的安全,可以使用反向代理提供WAF功能,阻止web攻击
(2)负载均衡,通过反向代理服务器来优化网站的负载

两者区别,看图说话:

负载均衡

基本概念:

这里提到的客户端发送的、Nginx 反向代理服务器接收到的请求数量,就是我们说的负载量。
请求数量按照一定的规则进行分发,到不同的服务器处理的规则,就是一种均衡规则。
所以将服务器接收到的请求按照规则分发的过程,称为负载均衡。

nginx负载均衡算法

Nginx提供的负载均衡策略有2种:内置策略和扩展策略。内置策略为轮询,加权轮询,Ip hash。
扩展策略,就天马行空,只有你想不到的没有他做不到的啦,你可以参照所有的负载均衡算法,给他一一找出来做下实现。
上2个图,理解这三种负载均衡算法的实现

Ip hash算法,对客户端请求的ip进行hash操作,然后根据hash结果将同一个客户端ip的请求分发给同一台服务器进行处理,可以解决session不共享的问题。

Nginx配置文件详解

Nginx配置文件主要分成四部分:main(全局设置)、server(主机设置)、upstream(上游服务器设置,主要为反向代理、负载均衡相关配置)和location(URL匹配特定位置后的设置),每部分包含若干个指令。

他们之间的关系式:server继承main,location继承server;upstream既不会继承指令也不会被继承。它有自己的特殊指令,不需要在其他地方的应用

main部分设置的指令将影响其它所有部分的设置;server部分的指令主要用于指定虚拟主机域名、IP和端口;upstream的指令用于设置一系列的后端服务器,设置反向代理及后端服务器的负载均衡;location部分用于匹配网页位置(比如,根目录”/“,”/images”,等等)。

docker run –name nginx-test -p 8080:80 -d nginx
使用docker命令直接安装启动nginx

1
2
3
4
5
6
# 进入容器内查看默认的配置文件,均在/etc/nginx/路径下。
localhost:~ liaoxb$ docker exec -ti 2ccbf7fa358e sh
# find / -name nginx.conf
/etc/nginx/nginx.conf
# find / -name default.conf
/etc/nginx/conf.d/default.conf

默认的 nginx 配置文件 nginx.conf 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
root@2ccbf7fa358e:/# cat /etc/nginx/nginx.conf
user nginx; #定义Nginx运行的用户和用户组

worker_processes 1; #nginx进程数,建议设置为等于CPU总核心数

error_log /var/log/nginx/error.log warn; #全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]

pid /var/run/nginx.pid; #进程pid文件



events {
worker_connections 1024; #单个进程最大连接数(最大连接数=连接数*进程数)
}

#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
include /etc/nginx/mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
sendfile on;
#此选项允许或禁止使用socke的TCP_CORK的选项,此选项仅在使用sendfile的时候使用
#tcp_nopush on;

keepalive_timeout 65; #长连接超时时间,单位是秒

#gzip on; #gzip模块设置

include /etc/nginx/conf.d/*.conf; #增加nginx虚拟主机配置文件(conf.d)
}

默认的nginx虚拟主机配置文件如下(反向代理到nginx的默认html页面,位于/usr/share/nginx/html/index.html):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
root@2ccbf7fa358e:/# cat /etc/nginx/conf.d/default.conf
#虚拟主机的配置
server {
listen 80; #监听端口
server_name localhost; #域名可以有多个,用空格隔开

#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
#对 "/" 启用反向代理
location / {
root /usr/share/nginx/html; #根目录
index index.html index.htm; #设置默认页
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all; #拒绝的ip
#}
}

参考文档:
https://www.runoob.com/w3cnote/nginx-setup-intro.html
https://www.runoob.com/w3cnote/nginx-setup-intro.html
https://www.w3cschool.cn/nginx/nginx-d1aw28wa.html

Linux Shell

Shell是这样的一个命令行工具(也称为终端或壳),充当的是人与内核之间的翻译官,用户把一些命令“告诉”终端,它就会调用相应的程序服务去完成某些工作。

Bash shell 功能

主流Linux系统选择Bash(Bourne-Again SHell)作为默认的Shell主要有以下4项优势

1、命令记忆功能

  • 通过上下方向键来调取过往执行过的Linux命令;
  • ~/.bash_history 记录的是前一次登陆以前所执行过的指令,而至于这一次登陆所执行的指令都被暂存在内存中,当用户成功登出系统后,该指令记忆才会记录到 .bash_history 当中

2、Tab键自动补全命令或文件

3、命令别名设置功能(alias)

4:程序化脚本(shell scripts)

output

Shell 变量

变量的设置规则:

  1. 变量名由字母、数字、下划线组成,不能以数字开头。变量名一般习惯用大写
  2. 等号两侧不能有空格
  3. 变量值若有空白字符,可使用双引号或单引号将变量内容结合起来
    • 双引号内的特殊字符如 $ 等,可以保有原本的特性
    • 单引号内的特殊字符则仅为一般字符(纯文本)
  4. 反斜杠\ 可以将后面的特殊符号(如 [Enter], $, , 空白字符, ‘等)变成一般字符串
  5. 反引号`` 或$()可以将其中的命令执行后返回结果
  6. 若该变量需要在其他子程序执行,则需要以 export 来使变量变成环境变量: export PATH

变量基本操作:

  1. 查看所有环境变量:env
  2. 查看单个变量:echo $PATHecho ${HOME}
  3. 定义变量:变量名=变量值
  4. 删除变量:unset 变量名
  5. 特殊符号变量:
    • $$:当前进程的 PID 进程号
    • $?:上个命令执行的回传值,0为执行成功,非0执行失败
    • $0:脚本文件名称
    • $#:脚本的参数个数
    • $@:代表 「"&1" "&2" "&3" "&4"」 的意思,每个变量是独立的(用双引号括起来)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 示例1:使用反斜杠(\)进行转义
[root@linuxprobe ~]# PRICE=5
[root@linuxprobe ~]# echo "Price is \$$PRICE"
Price is $5


# 示例2:将一个命令的执行结果赋值给变量(重点)
[root@node-1 ~]# A=`date`
[root@node-1 ~]# echo $A
2021年 12月 14日 星期二 01:22:02 CST

[root@node-1 ~]# A=$(date)
[root@node-1 ~]# echo $A
2021年 12月 14日 星期二 01:25:22 CST

# 示例3:单引号和双引号的使用区别
[root@node-1 ~]# NAME='liao xiaobo'
[root@node-1 ~]# NAME="My name is $NAME" # 双引号会保留特殊符号的含义
[root@node-1 ~]# echo $NAME
My name is liao xiaobo

[root@node-1 ~]# NAME2='My name is $NAME' # 单引号之间的内容原封不动的指定给了变量;
[root@node-1 ~]# echo $NAME2
My name is $NAME

Bash 的环境配置文件

bash 配置文件的读入方式是通过 source 指令来读取的。

整个 login shell 的读取流程如下:

/etc/profile:这是系统整体的设置,一般不需要修改这个文件;

~/.bash_profile~/.bash_login:属于登陆用户的个人设置

输入输出重定向

简而言之,输入重定向是指把文件导入到命令中,而输出重定向则是指把原本要输出到屏幕的数据信息写入到指定文件中。

在日常的学习和工作中,相较于输入重定向,我们使用输出重定向的频率更高,输出重定向分为标准输出重定向和错误输出重定向两种不同的技术,以及清空写入与追加写入两种模式。

输入重定向中用到的符号及其作用

符号 作用
命令 < 文件 将文件作为命令的标准输入
命令 << 分界符 从标准输入中读入,直到遇见分界符才停止
命令 < 文件1 > 文件2 将文件1作为命令的标准输入并将标准输出到文件2
1
2
3
4
5
6
# 远程执行本地shell脚本
ssh master02 'bash -s'< /opt/kill.sh

# 等同于cat admin-openrc.sh | wc -l的管道符命令组合
[root@master01 ~]# wc -l < admin-openrc.sh
11

输出重定向中用到的符号及其作用

符号 作用
命令 > 文件 将标准输出重定向到一个文件中(清空)
命令 2> 文件 将错误输出重定向到一个文件中(清空)
命令 >> 文件 将标准输出重定向到一个文件中(追加)
命令 2>> 文件 将错误输出重定向到一个文件中(追加)
命令 >> 文件 2>&1 或 命令 &>> 文件 将标准输出与错误输出共同写入到文件中(追加)

常用判断式

文件判断(类型、权限)

测试的标志 含义
-e 文件是否存在;常用
-f 该文件是否存在且为文件(file)?常用
-d 该文件是否存在且为目录(directory)?常用
-b 该文件是否存在且为一个 block device ?
-r 该文件是否存在且具有可读权限?
-w 该文件是否存在且具有可写权限?
-x 该文件是否存在且具有可执行权限?
-ef 判断 file1 与 file2 是否是同一文件,可用在判断 hard link 的判定上。主要意义在判定两个文件是否均指向同一个 inode

整数比较

整数比较运算符仅是对数字的操作,不能将数字与字符串、文件等内容一起操作,而且不能想当然地使用日常生活中的等号、大于号、小于号等来判断。

测试的标志 含义
-eq 两数值相等(equal)
-ne 不相等(not equal)
-gt 大于(greater than)
-lt 小于(less than)
-ge 大于等于(greater than or equal)
-le 小于等于(less than or equal)

字符串比较

测试的标志 含义
-z string 判定字符串是否为 0?若为空串,则为 true
-n string 判定字符串是否不为 0?若为空串,则为 false;注意:-n 可省略
str1 == str2 是否相等,相等则为 true
str1 != str2 是否不相等,相等则为 false

逻辑判断

测试的标志 含义
-a (and)两状况同时成立;如:test -r filename -a -x filename,则 file 同时具有 r 与 x 权限时才为 true
-o (or)任意一个成立。如:test -r filename -o -x filename,则 file 具有 r 或 x 权限时就为 true
! 反向状态

脚本执行方式差异

./script 或者 sh script执行:运行脚本时都会使用一个新的 bash 环境,即子程序的 bash 内执行。当子程序完成后,子程序内的各项变量或动作将会结束,不会传回到父程序中。

1
2
3
4
5
6
7
8
# 运行上面范例的姓名打印
[mrcode@study bin]$ ./showname.sh
Please input you first name: m
Please input you last name: q

Your full name is: mq # echo -e "\n Your full name is: ${firstname}${lastname}" 打印出来了信息
[mrcode@study bin]$ echo ${fristname}${lastname} # 但是在父程序中却没有信息

source 执行:同样的测试代码,使用 source 则会在父程序中执行

1
2
3
4
5
6
7
[mrcode@study bin]$ source showname.sh 
Please input you first name: m
Please input you last name: q

Your full name is: mq
[mrcode@study bin]$ echo ${firstname}${lastname}
mq # 在父程序中还能获取到

脚本练习

利用 date 进行文件的建立

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
# Program:
# 用户输入文件名前缀,生成前天、昨天、今天的三个空文件

echo -e "将使用 ‘touch’ 命令创建 3 个文件"
read -p "请输入文件名:" fileuser

# 容错,使用变量功能判定与赋值默认值
filename=${fileuser:-"filename"}

# date 命令的使用
date1=$(date --date='2 days ago' +%Y-%m-%d) # 两天前的日期,并格式化显示
date2=$(date --date='1 days ago' +%Y-%m-%d)
date3=$(date +%Y-%m-%d)

file1="${filename}_${date1}"
file2="${filename}_${date2}"
file3="${filename}_${date3}"

# 在这里其实可以直接拼接文件名
touch "${file1}"
touch "${file2}"
touch "${file3}"

数值运算:简单的加减乘除

在Linux变量中,需要使用 declare来定义变量为正数才能进行计算,此外,也可以利用 $((计算表达式)) 来进行数值运算,可惜的是,bashe shell 预设仅支持整数数据。

1
2
3
4
5
6
7
8
9
#!/bin/bash
# Program:
# 用户输入 2 个整数;输出相乘后的结果
read -p '请输入第一个整数:' intUser1
read -p '请输入第二个整数:' intUser2
declare -i int1=${intUser1}
declare -i int2=${intUser2}

echo -e "\n ${int1} x ${int2} = $((int1*int2))"

多重、复杂条件判断

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
# Program:
# 直接携带参数提示

if [ "$1" == "hello" ]; then
echo "Hello, how ary you?"
elif [ -z "$1" ]; then
echo "请携带参数"
else
echo "只能携带参数 hello"
fi

利用 case...esac 判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# Program:
# 直接携带参数提示

case $1 in
"hello")
echo "Hello, how ary you?"
;;
"")
echo "请携带参数"
;;
*)
echo "只能携带参数 hello"
;;
esac

Linux 文件系统

一切皆文件

“一切皆是文件”是 Unix/Linux 的基本哲学之一,它是指 Linux 系统中的所有的一切都可以通过文件的方式访问、管理,即使不是文件,也以文件的形式来管理。例如硬件设备、进程、套接字等都抽象成伪文件,使用统一的用户接口,虽然文件类型各不相同,但是对其提供的却是同一套操作。

在 Linux 中共有 7 种类型的文件,使用了不同的字符来加以区分,其中伪文件并不占用磁盘空间:

文件类型标识 文件类型
- 普通文件
d 目录文件
l 符号链接
c(伪文件) 字符设备(character device)
b(伪文件) 块设备(block device)
s(伪文件) 套接字文件(socket)
p(伪文件) 命名管道文件(pipe)

硬件设备命名

系统内核中的udev设备管理器会自动把硬件名称规范起来,目的是让用户通过设备文件的名字可以猜出设备大致的属性以及分区信息等;这对于陌生的设备来说特别方便。

硬件设备 文件名称
SCSI/SATA/U盘 /dev/sd[a-z]
virtio设备 /dev/vd[a-z](用于虚拟机内)
软驱 /dev/fd[0-7]
打印机 /dev/lp[0-15]
光驱CDROM /dev/sr[0-1] (通用,CentOS 较常见)/dev/cdrom (当前 CDROM)
鼠标 /dev/mouse
磁带机 /dev/st0或/dev/ht0

目录树结构

在Windows操作系统中,想要找到一个文件,要依次进入该文件所在的磁盘分区(也叫盘符),然后再进入该分区下的具体目录,最终找到这个文件。但是在Linux系统中并不存在C、D、E、F等盘符,Linux系统中的一切文件都是从“根”目录(/)开始的,并按照文件系统层次标准(FHS)采用倒树状结构来存放文件,以及定义了常见目录的用途。

Linux系统中常见的目录名称以及相应内容

目录名称 应放置文件的内容
/boot 开机所需文件—内核、开机菜单以及所需配置文件等
/dev 以文件形式存放任何设备与接口
/etc 配置文件
/home 用户主目录
/bin 存放单用户模式下还可以操作的[命令]
/lib 开机时用到的函数库,以及/bin与/sbin下面的命令要调用的函数
/sbin 开机过程中需要的命令
/media 用于挂载设备文件的目录
/opt 放置第三方的软件
/root 系统管理员的家目录
/srv 一些网络服务的数据文件目录
/tmp 任何人均可使用的“共享”临时目录
/proc 虚拟文件系统,例如系统内核、进程、外部设备及网络状态等
/usr/local 用户自行安装的软件
/usr/sbin Linux系统开机时不会使用到的软件/命令/[脚本]
/usr/share 帮助与说明文件,也可放置共享文件
/var 主要存放经常变化的文件,如日志
/lost+found 当文件系统发生错误时,将一些丢失的文件片段存放在这里

inode介绍

  • inode (索引节点)是 Linux/Unix 文件系统的基础。
  • stat 命令可以查看文件的 inode 信息,包括文件元信息(例如权限、大小、修改时间以及数据块位置)
  • inode 的访问速度非常快,Unix/Linux系统通过 inode 号码定位到文件的元数据信息,进而读取文件的块数据(4k、1M),无需遍历整个文件系统
  • inode 的数量是有限的,每个文件系统只能包含固定数量的 inode。这意味着当文件系统中的 inode 用完时,无法再创建新的文件或目录,即使磁盘上还有可用空间。因此,在创建文件系统时,需要根据文件和目录的预期数量来合理分配 inode 的数量。

硬链接和软链接

硬链接

在 Linux/类 Unix 文件系统中,每个文件和目录都有一个唯一的索引节点(inode)号,用来标识该文件或目录。但是,Unix/Linux系统允许,多个文件名指向同一个inode号码。

  • ln 命令用于创建硬链接
  • 硬链接和源文件的 inode 节点号相同,两者对文件系统来说是完全平等的(可以看作是互为硬链接,源头是同一份文件)
  • 只有删除了源文件和所有对应的硬链接文件,该文件才会被真正删除。
  • 硬链接具有一些限制,不能对目录以及不存在的文件创建硬链接,并且,硬链接也不能跨越文件系统。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@master01 ~]# ll -i /etc/crontab
268535884 -rw-r--r-- 1 root root 451 Mar 14 2020 /etc/crontab

[root@master01 ~]# ln /etc/crontab .

# 建立硬链接,链接数加1
[root@master01 ~]# ll -i /etc/crontab crontab
268535884 -rw-r--r-- 2 root root 451 Mar 14 2020 crontab
268535884 -rw-r--r-- 2 root root 451 Mar 14 2020 /etc/crontab

# 删除硬链接,链接数减1
[root@master01 ~]# rm -rf crontab
[root@master01 ~]# ll -i /etc/crontab
268535884 -rw-r--r-- 1 root root 451 Mar 14 2020 /etc/crontab

软链接

  • ln -s 命令用于创建软链接
  • 软链接和源文件的 inode 节点号不同,而是指向一个文件路径
  • 软连接类似于 Windows 系统中的快捷方式。即源文件删除后,软链接依然存在,但是指向的是一个无效的文件路径
  • 不同于硬链接,可以对目录或者不存在的文件创建软链接,并且,软链接可以跨越文件系统。
1
2
3
4
5
[root@master01 ~]# ln -s /etc/crontab crontab_test

[root@master01 ~]# ll -i /etc/crontab crontab_test
344677386 lrwxrwxrwx 1 root root 12 Jan 20 18:41 crontab_test -> /etc/crontab
268535884 -rw-r--r-- 1 root root 451 Mar 14 2020 /etc/crontab

在Linux系统上/bin/sh通常就是指向/bin/bash的软链接。

1
2
3
4
5
[root@master01 ~]# ll -i /bin/sh
872423134 lrwxrwxrwx 1 root root 4 Feb 20 2024 /bin/sh -> bash

[root@master01 ~]# ll -i /bin/bash
872423123 -rwxr-xr-x 1 root root 1166952 Feb 20 2024 /bin/bash

常用文件系统

XFS系统

XFS 是一种高性能的文件系统,相比 ext4,它在某些方面具有显著优势。如下:

  • 大文件处理:XFS 在处理大文件时性能优异,适合需要频繁读写大文件的场景(如视频编辑、数据库)。
  • 高并发:XFS 通过延迟分配(Delayed Allocation)和分布式 B+ 树索引,优化了高并发写入性能,特别是在多线程场景下,能够更好地利用多核 CPU,适合高并发工作负载。
  • 动态 inode 分配:XFS 可以动态分配 inode,而 ext4 需要在创建文件系统时预先分配 inode,可能导致 inode 不足和格式化速度慢的问题。
  • 高效的日志机制:XFS 的日志机制更高效,能够快速恢复文件系统一致性,尤其在系统崩溃后。

Linux 硬盘与文件系统管理

硬盘类型

机械硬盘(HDD)的组成主要有盘片、机械手臂、磁头与主轴马达所组成,而数据的写入其实是在盘片上面。盘片上面又可细分出扇区(Sector)与磁道(Track)两种单位,其中扇区的容量设计有两种大小,分别是 512Bytes 与 4KBytes。

固态硬盘(SSD)是基于半导体闪存(NAND Flash)作为存储介质的硬盘,相比传统的机械硬盘,它去掉了机械固件,引入了主控芯片来代替机械操作,这意味着它的性能、功耗及可靠性会比HDD高出一大截。固态硬盘虽然没有物理扇区,但逻辑上仍保留扇区的概念以兼容操作系统和文件系统。

关于硬盘的总结如下:

  • 扇区(Sector)为最小的物理储存单位,且依据磁盘设计的不同,目前主要有 512Bytes与 4K 两种格式;
  • 柱面(cylinder)是由多个盘片上处于同一磁道位置(即同一半径)的磁道组成的集合;

硬盘分区和挂载

分区工具
常用的分区工具有 fdiskparted、Windows 下的磁盘管理工具等。使用这些工具可以在硬盘上建立一个分区表,用于记录每个分区的起始位置、结束位置、大小及其它属性。

分区表类型

MBR(Master Boot Record):传统的分区表格式,最多支持4个主分区(或3个主分区加一个扩展分区,扩展分区内可创建多个逻辑分区)。

MBR 分区表中,第一个扇区最重要,里面有主开机记录(Master boot record,MBR)及分区表(partition table),其中 MBR 占有 446 Bytes,而 partition table 则占有 64 Bytes。

img

GPT(GUID Partition Table):现代硬盘常用的分区表格式,支持更多分区,且对于大容量硬盘有更好的支持和数据冗余能力。

分区过程
分区工具会让你选择起始扇区和结束扇区,从而决定每个分区的大小。现在的分区都是基于逻辑扇区(LBA)进行划分的。

  • 指定大小和位置:用户可以根据需要指定各个分区的大小和位置,确保不同的分区满足不同应用场景的需求。
  • 确定分区类型:通常会根据用途为分区分配不同的标记或文件系统类型(如Linux下的 ext4、swap 分区,Windows下的 NTFS 等)。
  • 写入分区表:完成分区配置后,工具会将信息写入硬盘的分区表中。以后系统启动时,就会根据这个分区表来识别和管理各个分区。

方法一:分区 → 格式化 → 挂载

使用步骤:

  1. 输入 n 创建新分区。
  2. 输入分区类型(如 primarylogical)。
  3. 设置起始和结束扇区(通常直接按回车使用默认值)。
  4. 输入 w 保存分区表并退出。
  5. 格式化分区
  6. 挂载分区
  7. 开机自动挂载(可选)

方法二:直接格式化→ 挂载

这种方法适合特定用途,例如非系统盘的大容量存储。

1
2
sudo mkfs.ext4 /dev/sdb
sudo mount /dev/sdb /mnt/data

方法三:使用 LVM(逻辑卷管理器)

如果需要灵活管理硬盘容量,可以使用 LVM:初始化 → 创建卷组 → 创建逻辑卷 → 格式化 → 挂载

1
2
3
4
5
6
7
8
9
10
# 初始化硬盘
sudo pvcreate /dev/sdb
# 创建卷组
sudo vgcreate my_vg /dev/sdb
# 创建逻辑卷
sudo lvcreate -L 50G -n my_lv my_vg
#格式化卷
sudo mkfs.ext4 /dev/my_vg/my_lv
#挂载卷
sudo mount /dev/my_vg/my_lv /mnt/data

方法四:作为裸设备使用

某些特殊用途(如数据库或存储系统)可能直接使用裸设备,无需分区和格式化。例如数据库(如 MySQL)可以直接将 /dev/sdb 作为数据存储路径。

硬盘阵列技术

RAID技术的设计初衷是减少因为采购硬盘设备带来的费用支出,但是与数据本身的价值相比较,现代企业更看重的则是RAID技术所具备的冗余备份机制以及带来的硬盘吞吐量的提升。也就是说,RAID不仅降低了硬盘设备损坏后丢失数据的几率,还提升了硬盘设备的读写速度,所以它在绝大多数运营商或大中型企业中得以广泛部署和应用。

RAID 特性

  • 协同工作:多块硬盘通过一定的 RAID 级别协同工作。
  • 性能提升:通过并行读写提高数据吞吐量(如 RAID 0、RAID 10)。
  • 可靠性增强:通过数据冗余提高数据安全性(如 RAID 1、RAID 5)。
  • 容量组合:多块硬盘的容量可以组合成一个逻辑卷。
  • 应用场景:适用于服务器、企业级存储、大型数据库系统等。

常见的 RAID 级别

RAID 级别 特点
RAID 0 数据交错存放,性能提升,但无数据冗余,一块硬盘损坏即丢失全部数据
RAID 1 两块硬盘存储相同数据,可靠性高但容量利用率低,若使用软件RAID,可能写入性能会变差
RAID 5 分布式校验数据,性能和可靠性均衡,需要至少 3 块硬盘;当一块磁盘损毁时,可以通过同位检查码重建数据
RAID 10 RAID 1+0,性能和可靠性均高,需要至少 4 块硬盘

软件 RAID

由于磁盘阵列有很多优秀的功能,然而硬件磁盘阵列卡偏偏又贵的很~因此就有发展出利用软件来仿真磁盘阵列的功能,这就是所谓的软件磁盘阵列(software RAID)。软件磁盘阵列主要是通过软件来仿真阵列的任务,因此会损耗较多的系统资源,比如说 CPU 的运算与I/O 总线的资源等。

硬件磁盘阵列(hardware RAID)是通过磁盘阵列卡来达成阵列的目的。磁盘阵列卡上面有一块专门的芯片在处理 RAID 的任务,因此在性能方面会比较好。

软件实现 RAID,通过 Linux 的 mdadm 工具配置软件 RAID。

1
sudo mdadm --create /dev/md0 --level=5 --raid-devices=3 /dev/sd[b-d]

nfs-server-install

NFS 是Network File System的缩写,即网络文件系统。功能是通过网络让不同的机器、不同的操作系统能够彼此分享个别的数据,让应用程序在客户端通过网络访问位于服务器磁盘中的数据,是在类Unix系统间实现磁盘文件共享的一种方法。
NFS在文件传送或信息传送过程中依赖于RPC协议。所以只要用到NFS的地方都要启动RPC服务,不论是NFS SERVER或者NFS CLIENT。这样SERVER和CLIENT才能通过RPC来实现PROGRAM PORT(centos5之前,之后是rpcbind)的对应。可以这么理解RPC和NFS的关系:NFS是一个文件系统,而RPC是负责信息的传输。

Centos系统环境:
服务端IP 192.168.1.28
客户端IP 192.168.1.21、192.168.1.155

一、安装NFS-Server

1
2
rpm -qa|grep nfs #检查系统是否已安装NFS
yum install nfs-utils -y #客户端和服务端都要安装

二、服务端配置启动NFS

1
2
3
4
5
6
7
8
9
mkdir /var/nfsshare 
vim /etc/exports #配置共享目录供客户端集群以读写权限访问
systemctl start nfs
showmount -e localhost //查询NFS的共享状态

[root@test--0004 ~]# showmount -e 192.168.1.28
Export list for 192.168.1.28:
/var/nfsshare2 *
/var/nfsshare *

说明:NFS服务的配置文件为/etc/exports,这个文件是NFS的主要配置文件,不过系统并没有默认值,所以这个文件不一定会存在,可能要使用vim手动建立,然后在文件里面写入配置内容。内容格式如下:

1
<输出目录> [客户端1 选项(访问权限,用户映射,其他)] [客户端2 选项(访问权限,用户映射,其他)]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1、输出目录:输出目录是指NFS系统中需要共享给客户机使用的目录;
2、客户端:客户端是指网络中可以访问这个NFS输出目录的计算机
客户端常用的指定方式:
指定ip地址的主机:192.168.8.106
指定子网中的所有主机:192.168.0.0/24或 192.168.0.0/255.255.255.0
指定域名的主机:wj.bsmart.com
指定域中的所有主机:*.bsmart.com
所有主机:*

3、 选项:选项用来设置输出目录的访问权限、用户映射等。

NFS主要有3类选项:

1)访问权限选项:

设置输出目录只读:ro
设置输出目录读写:rw

2)用户映射选项

all_squash:将远程访问的所有普通用户及所属组都映射为匿名用户或用户组(nfsnobody);
no_all_squash:与all_squash取反(默认设置);
root_squash:将root用户及所属组都映射为匿名用户或用户组(默认设置);
no_root_squash:与rootsquash取反;
anonuid=xxx:将远程访问的所有用户都映射为匿名用户,并指定该用户为本地用户(UID=xxx);
anongid=xxx:将远程访问的所有用户组都映射为匿名用户组账户,并指定该匿名用户组账户为本地用户组账户(GID=xxx);

3)其它选项

secure:限制客户端只能从小于1024的tcp/ip端口连接nfs服务器(默认设置);
insecure:允许客户端从大于1024的tcp/ip端口连接服务器;
sync:将数据同步写入内存缓冲区与磁盘中,效率低,但可以保证数据的一致性;
async:将数据先保存在内存缓冲区中,必要时才写入磁盘;
wdelay:检查是否有相关的写操作,如果有则将这些写操作一起执行,这样可以提高效率(默认设置);
no_wdelay:若有写操作则立即执行,应与sync配合使用;
subtree:若输出目录是一个子目录,则nfs服务器将检查其父目录的权限(默认设置);
no_subtree:即使输出目录是一个子目录,nfs服务器也不检查其父目录的权限,这样可以提高效率;

三、设置开机启动

1
2
systemctl enable rpcbind.service
systemctl enable nfs-service

四、测试挂载:

1
2
3
4
5
客户端执行:
mount -t nfs 192.168.1.28:/var/nfsshare /mnt #客户端挂载NFS服务器中的共享目录
touch /mnt/test.txt #客户端挂载点生成文件,此文件会被共享至NFS服务器:/var/nfsshare
echo "hello word" > /mnt/test.txt
umount /mnt #解除和NFS服务器的挂载

文件目录管理

grep

grep命令用于在文本中执行关键词搜索,并显示匹配的结果,格式为“grep [选项] [文件]”。

参数 作用
-b 将可执行文件(binary)当作文本文件(text)来搜索
-c 仅显示找到的行数
-i 忽略大小写
-n 显示行号
-v 反向选择——仅列出没有“关键词”的行。
-A 除了显示符合范本样式的那一行之外,并显示该行之后的内容。
-B 在显示符合范本样式的那一行之外,并显示该行之前的内容。
-C 除了显示符合范本样式的那一列之外,并显示该列之前后的内容。

awk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
localhost% cat test.txt
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s01 Ready wise-controller 38d v1.16.4 192.168.0.3 <none> CentOS 3.10.0-862.el7.x86_64 docker://18.9.8
k8s02 Ready wise-controller 38d v1.16.4 192.168.0.7 <none> CentOS 3.10.0-862.el7.x86_64 docker://18.9.8
k8s03 Ready wise-controller 38d v1.16.4 192.168.0.10 <none> CentOS 3.10.0-862.el7.x86_64 docker://18.9.8
k8s04 NotReady node 38d v1.16.4 192.168.0.15 <none> CentOS 3.10.0-862.el7.x86_64 docker://18.9.8

# 打印文件的第一列和第五列
localhost% awk '{print $1,$5}' test.txt
NAME VERSION
k8s01 v1.16.4
k8s02 v1.16.4
k8s03 v1.16.4
k8s04 v1.16.4

# 打印最后一列字段
localhost% awk '{print $NF}' test.txt
CONTAINER-RUNTIME
docker://18.9.8
docker://18.9.8
docker://18.9.8
docker://18.9.8

# 打印倒数第二列字段:
localhost% awk '{print $(NF-1)}' test.txt
KERNEL-VERSION
3.10.0-862.el7.x86_64
3.10.0-862.el7.x86_64
3.10.0-862.el7.x86_64
3.10.0-862.el7.x86_64

# 打印文本文件的总行数
localhost% awk 'END{print NR}' test.txt
5

# 打印文本第1行数据
localhost% awk 'NR==1{print}' test.txt
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME

# 打印文本大于第1行的数据
localhost% awk 'NR>1{print}' test.txt
k8s01 Ready wise-controller 38d v1.16.4 192.168.0.3 <none> CentOS 3.10.0-862.el7.x86_64 docker://18.9.8
k8s02 Ready wise-controller 38d v1.16.4 192.168.0.7 <none> CentOS 3.10.0-862.el7.x86_64 docker://18.9.8
k8s03 Ready wise-controller 38d v1.16.4 192.168.0.10 <none> CentOS 3.10.0-862.el7.x86_64 docker://18.9.8
k8s04 NotReady node 38d v1.16.4 192.168.0.15 <none> CentOS 3.10.0-862.el7.x86_64 docker://18.9.8

sed

定位到数据行并对数据进行增删改查操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 替换文本中的字符串:
sed 's/book/books/' file

# 使用后缀/g标记会替换每一行中的所有匹配:
[root@harbor image_pull_push]# cat img-list.txt |sed 's/registry.cn-hangzhou.aliyuncs.com/192.168.0.11/g'

# 当需要从第N处匹配配开始替换时,可以使用 /Ng:
echo sksksksksksk | sed 's/sk/SK/3g'
skskSKSKSKSK

# 替换某目录下所有文件的某字符串
oldip=172.22.12.241
newip=172.22.12.242
# 查看之前包含oldip的文件
find . -type f | xargs grep $oldip
# 替换IP地址
find . -type f | xargs sed -i "s/$oldip/$newip/"
# 检查更新后的
find . -type f | xargs grep $newip

find

find命令用于按照指定条件来查找文件,格式为“find [查找路径] 寻找条件 操作”。

参数 作用
-name 匹配名称
-perm 匹配权限(mode为完全匹配,-mode为包含即可)
-user 匹配所有者
-group 匹配所有组
-mtime -n +n 匹配修改内容的时间(-n指n天以内,+n指n天以前)
-atime -n +n 匹配访问文件的时间(-n指n天以内,+n指n天以前)
-ctime -n +n 匹配修改文件权限的时间(-n指n天以内,+n指n天以前)
-nouser 匹配无所有者的文件
-nogroup 匹配无所有组的文件
-newer f1 !f2 匹配比文件f1新但比f2旧的文件
-type b/d/c/p/l/f 匹配文件类型(后面的字幕字母依次表示块设备、目录、字符设备、管道、链接文件、文本文件)
-size 匹配文件的大小(+50KB为查找超过50KB的文件,而-50KB为查找小于50KB的文件)
-prune 忽略某个目录
-exec …… {}; 后面可跟用于进一步处理搜索结果的命令(下文会有演示)
1
2
3
4
5
6
7
8
9
10
11
# 查找当前目录下是否存在README.md 
find . -name README.md

# 查找etc目录是否存在以host开头的文件
find /etc -name host*

# 指定目录查找大于1G的文件
find / -size +1024M

# 当前目录搜索所有文件,文件内容 包含 “140.206.111.111” 的内容
find . -type f -name "*" | xargs grep "140.206.111.111"

echo

1
2
3
4
5
6
7
8
9
# 创建带有内容的文件
[root@harbor ~]# echo hello > new.yaml
[root@harbor ~]# cat new.yaml
hello
# 追加写入文件
[root@harbor ~]# echo hello-test >> new.yaml
[root@harbor ~]# cat new.yaml
hello
hello-test

dd

dd命令用于按照指定大小和个数的数据块来复制文件或转换文件,格式为“dd [参数]”。

Linux系统中有一个名为/dev/zero的设备文件,这个文件不会占用系统存储空间,但却可以提供无穷无尽的数据,因此可以使用它作为dd命令的输入文件,来生成一个指定大小的文件。

参数 作用
if 输入的文件名称,如果不指定if,默认就会从stdin中读取输入。
of 输出的文件名称,如果不指定of,默认就会将stdout作为默认输出。
bs 设置每个“块”的大小
count 设置要复制“块”的个数
1
2
3
4
5
# 从/dev/zero设备文件中取出一个大小为100M的数据块
[root@master01 ~]# dd if=/dev/zero of=sun.txt bs=100M count=1
1+0 records in
1+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.0580656 s, 1.8 GB/s
1
2
3
4
5
# 测试磁盘写入速度
[root@localhost ~]# dd if=/dev/zero of=/tmp/testfile bs=1G count=1 oflag=direct
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB) copied, 7.10845 s, 151 MB/s
1
2
3
4
5
# 测试磁盘读取速度
[root@localhost ~]# dd if=/tmp/testfile of=/dev/null bs=1G count=1 iflag=direct
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB) copied, 6.53009 s, 164 MB/s

tar

tar命令用于对文件进行打包压缩或解压,格式为“tar [选项] [文件]”。在Linux系统中,常见的文件格式比较多,其中主要使用的是.tar或.tar.gz或.tar.bz2格式。

参数 作用
-c 创建压缩文件
-x 解开压缩文件
-t 查看压缩包内有哪些文件
-z 用Gzip压缩或解压
-j 用bzip2压缩或解压
-v 显示压缩或解压的过程
-f 目标文件名
-p 保留原始的权限与属性
-P 使用绝对路径来压缩
-C 指定解压到的目录

命令示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 仅打包,不压缩!将 /home/vivek/bin/ 目录打包
tar -cvf /tmp/bin-backup.tar /home/vivek/bin/

# 打包 并使用 bzip2 算法压缩压缩
tar -jcvf /tmp/bin-backup.tar.bz2 /home/vivek/bin/

# 打包 并使用 gzip 算法压缩压缩
tar -zcvf /tmp/bin-backup.tar.gz /home/vivek/bin/

# 解压缩
tar -zxvf bin-backup.tar.gz

# 详细列举包里的所有文件
tar -tvf /opt/extra.tgz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
上下翻页:Ctrl+f、Ctrl+b
跳到当前行最后字符处:Fn+右键
跳到当前行最前面字符处:Fn+左键、0

查找字符串:/字符串 n继续查找
字符全局替换::%s/foo/bar/g :{作用范围}s/{目标}/{替换}/{替换标志}

x或X:删除一个字符,x删除光标后的,而X删除光标前的;
D:删除从当前光标到光标所在行尾的全部字符;
删除行:dd ndd(n代表删除或复制的行数)
复制行:yy nyy
粘贴行:p、P

复原前一个操作:u
重做上一个操作:ctrl+r
显示行号::set nu


Ctrl+u:向文件首翻半屏;
Ctrl+d:向文件尾翻半屏;
Ctrl+f:向文件尾翻一屏;
Ctrl+b:向文件首翻一屏;
Esc:从编辑模式切换到命令模式;
ZZ:命令模式下保存当前文件所做的修改后退出vi;
:行号:光标跳转到指定行的行首;
:$:光标跳转到最后一行的行首;

scp

scp命令 用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的。

1
2
3
4
5
# 从远程拷贝目录到本地
scp -r root@10.10.10.10:/opt/soft/mongodb /opt/soft/

# 上传本地目录到远程机器指定目录
scp -r /opt/soft/mongodb root@10.10.10.10:/opt/soft/scptest

vi

vi编辑器提供了丰富的内置命令,有些内置命令使用键盘组合键即可完成,有些内置命令则需要以冒号“:”开头输入。

常用内置命令如下:

命令 作用
dd 删除(剪切)光标所在整行
5dd 删除(剪切)从光标处开始的5行
yy 复制光标所在整行
5yy 复制从光标处开始的5行
u 撤销上一步的操作
p 将之前删除(dd)或复制(yy)过的数据粘贴到光标后面
D 删除光标处所在行尾的全部字符
x 删除光标处的一个字符
:set nu 显示行号
/string、?string 查找字符串,常结合n/N可以继续查找上一个、下一个字符串
:s/foo/bar/g 将当前光标所在行的所有foo替换成bar
:%s/foo/bar/g 将全文中的所有foo替换成bar
Fn+右键 光标跳到当前行最后一个字符
Fn+右键、0 光标跳到当前行第一个字符
Ctrl+f、Ctrl+b 上下翻页

file

file命令用于查看文件的类型,格式为“file 文件名”。

在Linux系统中,由于文本、目录、设备等所有这些一切都统称为文件,而我们又不能单凭后缀就知道具体的文件类型,这时就需要使用file命令来查看文件类型了。

1
2
3
4
5
[root@master01 ~]# file admin-openrc.sh
admin-openrc.sh: ASCII text

[root@master01 ~]# file /dev/sda
/dev/sda: block special (8/0)

wc

wc 命令用于统计指定文本的行数、字数、字节数,格式为“wc [参数] 文本”。

参数 作用
-l 只显示行数
-w 只显示单词数
-c 只显示字节数

网络管理

ip

ip命令 用来显示或操纵Linux主机的路由、网络设备、策略路由和隧道,是Linux下较新的功能强大的网络配置工具。

网卡配置

1
2
3
4
5
6
7
8
9
10
11
ip link                          # 显示网络接口信息
ip link set eth0 up # 开启网卡
ip link set eth0 down # 关闭网卡
ip link set eth0 promisc on # 开启网卡的混合模式
ip link set eth0 promisc offi # 关闭网卡的混合模式
ip link set eth0 txqueuelen 1200 # 设置网卡队列长度
ip link set eth0 mtu 1400 # 设置网卡最大传输单元

ip a # 显示网卡IP信息
ip a a 192.168.0.1/24 dev eth0 # 为eth0网卡添加IP地址192.168.0.1
ip a d 192.168.0.1/24 dev eth0 # 为eth0网卡删除一个IP地址192.168.0.1

ip命令配置网卡信息,在网卡或机器重启后配置会丢失。要想配置永久生效,那就要修改网卡配置文件。如下:

1
2
3
4
5
6
7
8
9
# 文件名对应网口名,CentOS 7\8 默认配置文件
[Linux]# vi /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE="eth0"
BOOTPROTO="static"
BROADCAST="192.168.0.255"
HWADDR="00:16:36:1B:BB:74"
IPADDR="192.168.0.100"
NETMASK="255.255.255.0"
ONBOOT="yes"

路由配置

1
2
3
4
5
6
7
8
ip r                         # 显示系统路由
ip r add default via 192.168.1.254 # 设置系统默认路由
ip r d default # 删除默认路由

ip r a 192.168.4.0/24 via 192.168.0.254 dev eth0 # 设置192.168.4.0网段的网关为192.168.0.254,数据走eth0接口
ip r a default via 192.168.0.254 dev eth0 # 设置默认网关为192.168.0.254
ip r d 192.168.4.0/24 # 删除192.168.4.0网段的网关
ip r d 192.168.1.0/24 dev eth0 # 删除路由

netstat

有时进程之间需要通信,需要开启一个socket,socket就是对外建立连接的一个窗口,然后借助TCP协议进行通信。但进行通信之前首先需要进程开启一个端口,这时就可以通过netstat命令查看开启的端口以及由哪个进程开启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#列出所有端口
netstat -a
#列出所有tcp端口
netstat -at
#列出所有udp端口
netstat -au
#只列出所有监听 udp 端口
netstat -lu
# 通过端口找进程ID
netstat -anp|grep 8081 | grep LISTEN|awk '{printf $7}'|cut -d/ -f1

-n或--numeric:直接使用ip地址,而不通过域名服务器;
-l或--listening:显示监控中的服务器的Socket
-p或--programs:添加“PID/进程名称”到netstat输出中;

ss

ss 可以用来获取socket统计信息,它可以显示和netstat类似的内容。但ss的优势在于它能够显示更多更详细的有关TCP和连接状态的信息,而且比netstat更快速更高效。

1
2
3
4
5
6
ss -t -a    # 显示TCP连接
ss -u -a # 显示所有UDP Sockets
ss -s # 显示 Sockets 摘要
ss -l # 列出所有打开的网络连接端口
ss -pl # 查看进程使用的socket
ss -lp | grep 3306 # 找出打开套接字/端口应用程序

系统管理

firewalld-cmd

firewalld是centos7的一大特性,最大的好处有两个:支持动态更新,不用重启服务;第二个就是加入了防火墙的“zone”概念。

firewalld自身并不具备防火墙的功能,而是和iptables一样需要通过内核的netfilter来实现,也就是说firewalld和 iptables一样,他们的作用都是用于维护规则,而真正使用规则干活的是内核的netfilter,只不过firewalld和iptables的结 构以及使用方法不一样罢了。

1
2
3
4
5
6
7
8
9
10
11
[root@master01 ~]# firewall-cmd --zone=public --list-ports
2121/tcp 3306/tcp 8081/tcp 30000/tcp 38060/tcp 40000/tcp 40001/tcp

[root@master01 ~]# firewall-cmd --permanent --add-port=3307/tcp --zone=public
success

[root@master01 ~]# firewall-cmd --reload
success

[root@master01 ~]# firewall-cmd --zone=public --list-ports
2121/tcp 3306/tcp 3307/tcp 8081/tcp 30000/tcp 38060/tcp 40000/tcp 40001/tcp

firewalld中常见的zone(默认为public)以及相应的策略规则如下所示:

区域 默认规则策略
trusted 允许所有的数据包
home 拒绝流入的流量,除非与流出的流量相关;而如果流量与ssh、mdns、ipp-client、amba-client与dhcpv6-client服务相关,则允许流量
internal 等同于home区域
work 拒绝流入的流量,除非与流出的流量相关;而如果流量与ssh、ipp-client与dhcpv6-client服务相关,则允许流量
public 拒绝流入的流量,除非与流出的流量相关;而如果流量与ssh、dhcpv6-client服务相关,则允许流量
external 拒绝流入的流量,除非与流出的流量相关;而如果流量与ssh服务相关,则允许流量
dmz 拒绝流入的流量,除非与流出的流量相关;而如果流量与ssh服务相关,则允许流量
block 拒绝流入的流量,除非与流出的流量相关
drop 拒绝流入的流量,除非与流出的流量相关

ps

ps命令 用于报告当前系统的进程状态。

参数 作用
-a 显示所有进程(包括其他用户的进程)
-u 用户以及其他详细信息
-x 显示没有控制终端的进程
1
2
3
4
5
6
# 加上ww可以完整展示进程的信息
ps -efww
# 找出占用内存资源最多的前 10 个进程
ps -auxf | sort -nr -k 4 | head -10
# 找出占用cpu资源最多的前 10 个进程
ps -auxf | sort -nr -k 3 | head -10

journalctl

检索 systemd 日志,是 CentOS 7 才有的工具

1
2
3
# 查看服务启动日志
journalctl -u kubelet.service
journalctl -u etcd.service -f -n 100

如果不知道服务名称,可以使用systemctl list-units --type=service命令来列出系统中的 systemd 服务。

watch

watch命令 以周期性的方式执行给定的指令,指令输出以全屏方式显示

1
2
# 每隔60s查看主机内存的使用情况
watch -d -n 60 "free -h"

rpm

rpm命令 是RPM软件包的管理工具

1
2
3
4
5
6
7
8
# 列出所有安装过的包
rpm -qa

# 安装rpm软件包
rpm -ivh your-package.rpm

# 获取rpm包中的文件安装路径
rpm -ql nfs-utils-1.3.0-0.54.el7.x86_64

crontab

crontab命令 被用来提交和管理用户的需要周期性执行的任务

用户可以使用 crontab 工具来定制自己的计划任务。所有用户定义的crontab文件都被保存在/var/spool/cron目录中。其文件名与用户名一致。

crontab文件的含义:用户所建立的crontab文件中,每一行都代表一项任务,每行的每个字段代表一项设置,它的格式共分为六个字段,前五段是时间设定段,第六段是要执行的命令段,格式如下:

1
minute   hour   day   month   week   command     顺序:分 时 日 月 周
1
2
3
4
5
6
7
8
9
10
11
12
[root@master01 ~]# cat /var/spool/cron/root
#Ansible: release free
0 * * * * sh /opt/free.sh
#Ansible: disk check over 85% move vip
0 * * * * sh /opt/diskcheck.sh

# 列出该用户的定时任务
[root@master01 ~]# crontab -l
#Ansible: release free
0 * * * * sh /opt/free.sh
#Ansible: disk check over 85% move vip
0 * * * * sh /opt/diskcheck.sh

进阶操作

nohup

nohup命令 可以将程序以忽略挂起信号的方式运行起来,被运行的程序的输出信息将不会显示到终端。

1
2
# 后台运行脚本,stderr和stdout重定向输出到output.log
nohup sh install.sh > output.log 2>&1 &

script

script 用于在终端会话中,记录用户的所有操作和命令的输出信息。

使用命令exit或者快捷键Ctrl + D停止记录。

1
2
# 静默模式记录
script -q myfile

chattr

chattr命令 用来改变文件属性。这些属性共有以下8种模式:

1
2
3
4
5
6
7
8
9
10
11
12
a:让文件或目录仅供附加用途;
b:不更新文件或目录的最后存取时间;
c:将文件或目录压缩后存放;
d:将文件或目录排除在倾倒操作之外;
i:不得任意更动文件或目录;
s:保密性删除文件或目录;
S:即时更新文件或目录;
u:预防意外删除。

+<属性>:开启文件或目录的该项属性;
-<属性>:关闭文件或目录的该项属性;
=<属性>:指定文件或目录的该项属性。

用chattr命令防止系统中某个关键文件被修改:

1
chattr +i /etc/fstab

然后试一下rm、mv、rename等命令操作于该文件,都是得到Operation not permitted的结果。

让某个文件只能往里面追加内容,不能删除,一些日志文件适用于这种操作:

1
chattr +a /var/log/ansible.log
0%