CentOS7 安装 Openvpn

环境

角色 主机名 操作系统 IP
vpn 服务端 vpn-server CentOS7 192.168.1.90
vpn 客户端 vpn-client CentOS7 192.168.1.91

两台服务器初始准备

  • 关闭 SELinux
  • 关闭防火墙或放行 udp 端口 1194
  • 安装 openvpn
    1
    2
    3
    4
    
    yum install epel-release
    yum clean all
    yum makecache fast
    yum install easy-rsa openvpn
    

在 vpn-server 上创建证书

  • 复制 easy-rsa 脚本到 /opt/easy-rsa/ 下
    1
    2
    3
    
    cp -af /usr/share/easy-rsa/3.0.3/ /opt/easy-rsa
    # vars 文件包含证书相关配置,可修改
    cp /usr/share/doc/easy-rsa-3.0.3/vars.example /opt/easy-rsa/vars
    
  • 初始化 pki 目录结构
    1
    2
    
    cd /opt/easy-rsa
    ./easyrsa init-pki
    
  • 修改 /opt/easy-rsa/pki/safessl-easyrsa.conf 中如下配置,增加证书有效时间为 10 年
    1
    2
    
    default_days = 3650
    default_crl_days = 3650
    
  • 生成免密 ca 证书
    1
    2
    
    # 使用默认 common name 即可
    ./easyrsa build-ca nopass
    
  • 生成服务端免密证书
    1
    2
    
    # 参数 my-server0 指定生成的客户端证书文件名及其 common name
    ./easyrsa build-server-full my-server0 nopass
    
  • 生成客户端免密证书
    1
    2
    3
    4
    
    # 参数 my-client0 指定生成的客户端证书文件名及其 common name
    # 不同的客户端需指定不同的 common name
    # 方便在 client-conf-dir 目录下创建对应的同名客户端配置文件
    ./easyrsa build-client-full my-client0 nopass
    
  • 生成 dh.pem
    1
    
    ./easyrsa gen-dh
    
  • 生成 ta.key
    1
    
    openvpn --genkey --secret pki/ta.key
    
  • 查看证书目录
     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
    
    /opt/easy-rsa/
    ├── easyrsa
    ├── openssl-1.0.cnf
    ├── pki
       ├── ca.crt
       ├── certs_by_serial
          ├── 1835C740AD1421868300998618C0641F.pem
          └── 4F3AF1ED7D42ED56CCF26CC7622F4F50.pem
       ├── dh.pem
       ├── index.txt
       ├── index.txt.attr
       ├── index.txt.attr.old
       ├── index.txt.old
       ├── issued
          ├── my-client0.crt
          └── my-server0.crt
       ├── private
          ├── ca.key
          ├── my-client0.key
          └── my-server0.key
       ├── reqs
          ├── my-client0.req
          └── my-server0.req
       ├── serial
       ├── serial.old
       └── ta.key
    ├── vars
    └── x509-types
        ├── ca
        ├── client
        ├── COMMON
        ├── san
        └── server
    
  • 该证书目录 /opt/easyrsa 需妥善保管,后期增加其他客户端证书时会用到

配置 vpn-server

  • 开启路由转发,修改 /etc/sysctl.conf
    1
    2
    
    sysctl -w 'net.ipv4.ip_forward = 1'
    sysctl -p
    
  • 复制服务端证书到 openvpn 配置目录下
    1
    2
    3
    4
    
    mkdir -p /etc/openvpn/server/my-server0/
    cd /opt/easy-rsa/pki
    cp ca.crt dh.pem issued/my-server0.crt private/my-server0.key ta.key \
        /etc/openvpn/server/my-server0/
    
  • 创建 /etc/openvpn/server/my-server0.conf
    1
    2
    
    cd /usr/share/doc/openvpn-2.4.7/sample/sample-config-files
    cp server.conf /etc/openvpn/server/my-server0.conf
    
  • 修改 /etc/openvpn/server/my-server0.conf
    1
    2
    3
    4
    5
    
    ca my-server0/ca.crt
    cert my-server0/my-server0.crt
    key my-server0/my-server0.key
    dh my-server0/dh.pem
    tls-auth my-server0/ta.key 0
    

启动 vpn-server 服务

  • 启动 openvpn-server@my-server0.service 服务
    1
    
    systemctl start openvpn-server@my-server0.service
    
  • 如需提供 ca 密码
    1
    
    systemd-tty-ask-password-agent --query
    

配置 vpn-client

  • 复制 vpn-server 上的客户端证书到 openvpn 配置目录下
    1
    2
    
    mkdir -p /etc/openvpn/client/my-client0
    scp vpn-server:/opt/easy-rsa/pki/{ca.crt,issued/my-client0.crt,private/my-client0.key,ta.key} /etc/openvpn/client/my-client0/
    
  • 创建 /etc/openvpn/client/my-client0.conf
    1
    2
    
    cd /usr/share/doc/openvpn-3.0.3/sample/sample-config-files
    cp client.conf /etc/openvpn/client/my-client0.conf
    
  • 修改 /etc/openvpn/client/my-client0.conf
    1
    2
    3
    4
    5
    
    remote 192.168.1.90 1194 # vpn server 地址
    ca my-client0/ca.crt
    cert my-client0/client.crt
    key my-client0/client.key
    tls-auth my-client0/ta.key 1
    

启动 vpn-client 服务

  • 启动 openvpn-client@my-client0 服务
    1
    
    systemctl start openvpn-client@my-client0.service
    
  • 如需提供 ca 密码
    1
    
    systemd-tty-ask-password-agent --query
    

验证

  • vpn server 新增网卡 tun0,地址是 10.8.0.1/24
  • vpn client 新增网卡 tun0,地址是 10.8.0.2/24

参考

K8s 二进制安装

环境

角色 主机名 内网 IP 集群 IP 操作系统 服务 执行目录
部署机 k8s-master master120 10.0.4.120 - CentOS kube-apiserver kube-scheduler kube-controller-manager /opt/kubernetes/
etcd-node etcd121 10.0.4.121 10.10.10.121 CentOS etcd /opt/etcd/
etcd-node etcd122 10.0.4.122 10.10.10.122 CentOS etcd /opt/etcd/
etcd-node etcd123 10.0.4.123 10.10.10.123 CentOS etcd /opt/etcd/
k8s-node node124 10.0.4.124 - CentOS docker flannel kubelet kube-proxy /opt/kubernetes/
k8s-node node125 10.0.4.125 - CentOS docker flannel kubelet kube-proxy /opt/kubernetes/
k8s-node node126 10.0.4.126 - CentOS docker flannel kubelet kube-proxy /opt/kubernetes/

前期准备

  • 全部服务器关闭 firewalld 和 selinux,禁用 swap,部署机(master120)可免密 ssh 登陆其他服务器
  • 软件版本
    • CentOS: 7.7
    • etcd: 3.3.18
    • docker: ce-19.03.5
    • flannel: 0.11.0
    • kubernetes: 1.17.2
  • k8s牵扯到多个网段,这里说明下
    • 10.0.4.0/24 该网段是服务器物理网卡 IP 地址段,通过该地址访问互联网
    • 10.10.10.0/24 该网段是杜撰的,但也配置在服务器物理网卡上,用于 etcd 集群节点间通信,与 k8s 集群无关
    • 10.10.9.0/24 该网段是杜撰的,分配 k8s service 的 clusterIP
    • 172.17.0.0/24 该网段是杜撰的,是 docker 网桥自带网段,也是 flannel 提供的网段,实现不同节点间的容器互通
    • 172.16.0.0/24 该网段是杜撰的,是 k8s pod 的 IP 地址区间,用于区别流量来源

部署 etcd 集群

  • 在部署机(master120)上操作下面步骤

K8s 部署 Coredns 组件

环境

生成 service account 文件

  • 创建 0.coredns-sa.yml
    1
    2
    3
    4
    5
    6
    7
    
    cat > 0.coredns-sa.yml <<EOF
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: coredns
      namespace: kube-system
    EOF
    

生成 rbac 文件

  • 创建 1.coredns-rbac.yml
     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
    
    curl > 1.coredns-rbac.yml <<EOF
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      labels:
        kubernetes.io/bootstrapping: rbac-defaults
      name: system:coredns
    rules:
    - apiGroups:
      - ""
      resources:
      - endpoints
      - services
      - pods
      - namespaces
      verbs:
      - list
      - watch
    - apiGroups:
      - ""
      resources:
      - nodes
      verbs:
      - get
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      annotations:
        rbac.authorization.kubernetes.io/autoupdate: "true"
      labels:
        kubernetes.io/bootstrapping: rbac-defaults
      name: system:coredns
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:coredns
    subjects:
    - kind: ServiceAccount
      name: coredns
      namespace: kube-system
    EOF
    

生成 configmap 文件

  • 创建 2.coredns-configmap.yml
     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
    
    cat > 2.coredns-configmap.yml <<EOF
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: coredns
      namespace: kube-system
    data:
      Corefile: |
        .:53 {
            errors
            health {
              lameduck 5s
            }
            ready
            kubernetes cluster.local 10.10.9.0/24 {
              fallthrough in-addr.arpa ip6.arpa
            }
            prometheus :9153
            forward . /etc/resolv.conf
            cache 30
            loop
            reload
            loadbalance
        }
    EOF
    
  • 这里的 10.10.9.0/24 应与 kube-apiserver 配置文件中的 service-cluster-ip-range 一致
  • 这里的 cluster.local 应与 kubelet 配置文件中的 clusterDomain 一致

生成 deployment 文件

  • 创建 3.coredns-deployment.yml
     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
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    
    cat > 3.coredns-deployment.yml <<EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: coredns
      namespace: kube-system
      labels:
        k8s-app: kube-dns
        kubernetes.io/name: "CoreDNS"
    spec:
      # replicas: not specified here:
      # 1. Default is 1.
      # 2. Will be tuned in real time if DNS horizontal auto-scaling is turned on.
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxUnavailable: 1
      selector:
        matchLabels:
          k8s-app: kube-dns
      template:
        metadata:
          labels:
            k8s-app: kube-dns
        spec:
          priorityClassName: system-cluster-critical
          serviceAccountName: coredns
          tolerations:
            - key: "CriticalAddonsOnly"
              operator: "Exists"
          nodeSelector:
            beta.kubernetes.io/os: linux
          affinity:
            podAntiAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
              - labelSelector:
                  matchExpressions:
                  - key: k8s-app
                    operator: In
                    values: ["kube-dns"]
                topologyKey: kubernetes.io/hostname
          containers:
          - name: coredns
            image: coredns/coredns:1.6.6
            imagePullPolicy: IfNotPresent
            resources:
              limits:
                memory: 170Mi
              requests:
                cpu: 100m
                memory: 70Mi
            args: [ "-conf", "/etc/coredns/Corefile" ]
            volumeMounts:
            - name: config-volume
              mountPath: /etc/coredns
              readOnly: true
            ports:
            - containerPort: 53
              name: dns
              protocol: UDP
            - containerPort: 53
              name: dns-tcp
              protocol: TCP
            - containerPort: 9153
              name: metrics
              protocol: TCP
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                add:
                - NET_BIND_SERVICE
                drop:
                - all
              readOnlyRootFilesystem: true
            livenessProbe:
              httpGet:
                path: /health
                port: 8080
                scheme: HTTP
              initialDelaySeconds: 60
              timeoutSeconds: 5
              successThreshold: 1
              failureThreshold: 5
            readinessProbe:
              httpGet:
                path: /ready
                port: 8181
                scheme: HTTP
          dnsPolicy: Default
          volumes:
            - name: config-volume
              configMap:
                name: coredns
                items:
                - key: Corefile
                  path: Corefile
    EOF
    
  • coredns/coredns:1.2.2 该镜像可以提前导入本地局域网中的私有 docker 仓库中
  • 查看 k8s 对应的 coredns 版本,参考 coredns

生成 service 文件

  • 创建 4.coredns-service.yml
     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
    
    cat > 4.coredns-service.yml <<EOF
    apiVersion: v1
    kind: Service
    metadata:
      name: kube-dns
      namespace: kube-system
      annotations:
        prometheus.io/port: "9153"
        prometheus.io/scrape: "true"
      labels:
        k8s-app: kube-dns
        kubernetes.io/cluster-service: "true"
        kubernetes.io/name: "CoreDNS"
    spec:
      selector:
        k8s-app: kube-dns
      clusterIP: 10.10.9.2
      ports:
      - name: dns
        port: 53
        protocol: UDP
      - name: dns-tcp
        port: 53
        protocol: TCP
      - name: metrics
        port: 9153
        protocol: TCP
    EOF
    
  • 这里的 clusterIP 需与 kubelet 配置文件中的 clusterDNS 一致

部署到 kubernetes 中

  • 使用 kubectl 直接应用
    1
    2
    3
    4
    5
    
    kubectl apply -f 0.coredns-sa.yml
    kubectl apply -f 1.coredns-rbac.yml
    kubectl apply -f 2.coredns-configmap.yml
    kubectl apply -f 3.coredns-deployment.yml
    kubectl apply -f 4.coredns-service.yml
    

查看 coredns 状态

  • 查看 service 状态

CentOS7 系统盘迁移

环境

  • 两台服务器(A,B)
  • A 已安装好 CentOS7,且已关闭 selinux
  • B 裸机,待安装操作系统

打包根分区

  • 从 B 上拆下系统硬盘,接在 A 上,启动 A
  • 清空日志(推荐)
    1
    2
    
    cd /var/log/
    find . -type f | xargs rm -f
    
  • 关闭 selinux
    1
    
    sed -i '/^SELINUX=/cSELINUX=disabled' /mnt/etc/selinux/config
    
  • 如果 A 是 MBR 启动,则直接打包根分区
    1
    
    tar zcpf /centos7.tgz --exclude=/centos7.tgz --one-file-system /
    
  • 如果 A 是 EFI 启动,则需打包根分区和 EFI 分区
    1
    2
    
    # 假设 efi 分区挂载在 /boot/efi 下
    tar zcpf /centos7.tgz --exclude=/centos7.tgz --one-file-system / /boot/efi
    

硬盘分区

  • 假设 /dev/sdb 是 B 的系统硬盘
  • MBR 启动时,分区表是 dos,只分一个根分区即可
  • EFI 启动时,分区表是 gpt,需要分一个 512MB 的 efi 分区和一个根分区
    1
    2
    3
    
    fdisk /dev/sdb
    # n 创建新分区
    # t 指定分区类型 1 (即 efi system)
    

格式化

  • MBR 启动
    1
    
    mkfs.xfs /dev/sdb1
    
  • EFI 启动
    1
    2
    
    mkfs.vfat -F32 /dev/sdb1
    mkfs.xfs /dev/sdb2
    

挂载硬盘

  • MBR 启动
    1
    
    mount /dev/sdb1 /mnt/
    
  • EFI 启动
    1
    2
    3
    
    mount /dev/sdb2 /mnt/
    mkdir -p /mnt/boot/efi
    mount /dev/sdb1 /mnt/boot/efi/
    

部署操作系统

  • 解压之前打包的 /centos7.tgz
    1
    
    tar zxpf /centos7.tgz -C /mnt/
    
  • 替换 fstab 中的 uuid 信息
    1
    2
    3
    
    # 获取 B 的系统硬盘分区的 uuid 信息
    lsblk -f /dev/sdb
    # 把结果中的 uuid 替换到 /mnt/etc/fstab 中的相应位置
    
  • 如果打包时未关闭 selinux,此时可以修改配置文件
    1
    
    sed -i '/^SELINUX=/cSELINUX=disabled' /mnt/etc/selinux/config
    
  • 删除网卡硬件标识(推荐)
    1
    
    sed -i -e '/HWADDR/d' -e '/UUID/d' /mnt/etc/sysconfig/network-scripts/ifcfg-{eth,enp}*
    
  • 删除 ssh 主机密钥(推荐)
    1
    
    rm -rf /etc/ssh/ssh_host_*
    

部署 grub

  • MBR 启动
    1
    2
    3
    4
    5
    6
    7
    
    mount --bind /dev/ /mnt/dev/
    mount -t proc procfs /mnt/proc/
    mount -t sysfs sysfs /mnt/sys/
    chroot /mnt
    grub2-install /dev/sdb
    grub2-mkconfig -o /boot/grub2/grub.cfg
    exit
    
  • EFI 启动
    1
    2
    3
    4
    5
    6
    7
    8
    
    mount --bind /dev/ /mnt/dev/
    mount -t proc procfs /mnt/proc/
    mount -t sysfs sysfs /mnt/sys/
    mount -t efivarfs efivarfs /target/sys/firmware/efi/efivars/
    chroot /mnt
    efibootmgr -c -p 1 -d /dev/sdb -L "centos"
    grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
    exit
    

启动操作系统

  • 卸载 B 的系统硬盘
    1
    
    umount -R /mnt
    
  • 关闭 A,拆下刚部署好操作系统的硬盘,接回 B 中
  • 启动 B,刚部署的 CentOS7 正常启动

参考

CentOS7 安装 Cassandra 集群

环境

主机名 Public IP Cluster IP 操作系统 Cassandra 版本
cassandra101 10.0.4.101 10.10.10.101 CentOS7.6 3.0.18
cassandra102 10.0.4.102 10.10.10.102 CentOS7.6 3.0.18
cassandra103 10.0.4.103 10.10.10.103 CentOS7.6 3.0.18

各节点初始配置

  • 关闭 selinux、防火墙
  • 部署 java 运行环境
  • 创建 cassandra 用户
    1
    
    useradd -m cassandra
    
  • 创建数据目录
    1
    2
    3
    4
    5
    6
    
    cd /var/lib
    mkdir -p cassandra/data1 #多个存储磁盘可以创建多个数据存储目录
    mkdir -p cassandra/hints #建议与数据磁盘分开
    mkdir -p cassandra/commitlog #建议与数据磁盘分开
    mkdir -p cassandra/saved_caches #建议与数据磁盘分开
    chown -R cassandra.cassandra cassandra/
    
  • 创建日志目录
    1
    2
    3
    
    cd /var/log
    mkdir -p cassandra
    chown -R cassandra.cassandra cassandra/
    
  • 创建 pid 目录
    1
    2
    3
    
    cd /run
    mkdir -p cassandra
    chown -R cassandra.cassandra cassandra/
    
  • 增加 sysctl.conf 配置,执行 sysctl -p 生效
    1
    
    vm.max_map_count=1048576
    
  • 安装 jemalloc (推荐)
    1
    
    yum install jemalloc
    
  • 创建文件 /usr/lib/systemd/system/cassandra.service,内容如下
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    [Unit]
    Description=Cassandra
    Requires=network.service
    After=network.service
    [Service]
    Type=forking
    WorkingDirectory=/opt/cassandra
    Environment=JAVA_HOME=/opt/jre
    Environment=LOCAL_JMX=no
    PIDFile=/run/cassandra/cassandra.pid
    ExecStart=/opt/cassandra/bin/cassandra -p /run/cassandra/cassandra.pid
    User=cassandra
    Group=cassandra
    LimitNOFILE=65536
    LimitNPROC=65536
    LimitMEMLOCK=infinity
    SuccessExitStatus=143
    [Install]
    WantedBy=multi-user.target
    

部署 Cassandra

  • 登陆 cassandra101,下载 cassandra,解压至 /opt/ 下
  • 修改 /opt/cassandra/conf/cassandra.yaml
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    cluster_name: CassandraCluster
    hists_directory: /var/lib/cassandra/hints
    data_file_directories:
        - /var/lib/cassandra/data1
    commitlog_directory: /var/lib/cassandra/commitlog
    saved_caches_directory: /var/lib/cassandra/saved_caches
    seed_provider:
        - class_name: org.apache.cassandra.locator.SimpleSeedProvider
          parameters:
              - seeds: "10.10.10.101,10.10.10.102,10.10.10.103"
    listen_address: 10.10.10.101
    rpc_address: 10.0.4.101
    
  • 修改 /opt/cassandra/conf/logback.xml
    1
    
    sed -i 's,\${cassandra.logdir},/var/log,' /opt/cassandra/conf/logback.xml
    
  • 修改 /opt/cassandra/conf/cassandra-env.sh
    1
    2
    
    # 这里我暂时关闭了 jmx 远程验证,否则需要手动创建 jmxremote.password 文件
    sed -i 's/jmxremote.authenticate=true/jmxremote.authenticate=false/' /opt/cassandra/conf/cassandra-env.sh
    
  • 修改 cassandra 目录的权限
    1
    
    chown -R cassandra.cassandra cassandra/
    
  • 打包 cassandra 目录,部署到 cassandra102 和 cassandra103 的 /opt 下,并修改 cassandra.yaml
    1
    2
    3
    4
    5
    6
    
    # cassandra102
    listen_address: 10.10.10.102
    rpc_address: 10.0.4.102
    # cassandra103
    listen_address: 10.10.10.103
    rpc_address: 10.0.4.103
    

启动集群

  • 启动 cassandra 服务
    1
    2
    3
    
    
    systemctl daemon-reload
    systemctl start cassandra
    

简单使用

  • cqlsh 连接数据库
    1
    2
    
    /opt/cassandra/bin/cqlsh 10.0.4.101 9042
    cqlsh> desc keyspaces;
    

注意事项

  • 创建包含复合主键的表
    1
    2
    3
    4
    5
    6
    7
    8
    
    create table t1 (
        c1 text,
        c2 text,
        c3 text,
        c4 text,
        c5 text,
        primary key((c1,c2),c3,c4)
    );
    
  • 复合主键的第一列 “(c1,c2)” 构成 PartitionKey,其余列 c3,c4 都是 ClusteringKey
  • Cassandra 对 PartitionKey 计算 Hash 值,决定该记录的存放 node,ClusteringKey 在 Partition 内部排序
  • 默认只支持主键列索引列查询,否则需要手动指定 allow filtering
  • 根据多个 ClustringKey 查询时,需指定全部的 PartitionKey,ClusteringKey 不能跳过
  • 主键列不可修改

sed 命令

流程

  • 每次从输入中读取一行
  • 匹配数据
  • 修改数据
  • 输出数据(默认 stdout)

选项

  • -e 执行多个编辑命令
    1
    2
    
    sed -e 's/root/ROOT/g; s/bin/BIN/g' /etc/passwd
    sed -e 's/root/ROOT/g' -e 's/bin/BIN/g' /etc/passwd
    
  • -f 从指定文件中获取 sed 命令
    1
    2
    3
    4
    5
    6
    
    cat > script.sed <<EOF
    s/root/ROOT/
    s/bin/BIN/
    s/home/HOME/
    EOF
    sed -f script.sed /etc/passwd
    
  • -n 不输出数据(只是编辑器不输出,与编辑命令无关)
  • -i 直接修改文件本身
  • -r 扩展正则表达式,不需要繁琐的转义

命令

命令 描述
s 替换文本
d 删除行
i 匹配行上插入新行
a 匹配行下插入新行
c 匹配行替换
y 逐个字符替换文本
p 打印行
= 打印行号
w 写入指定文件
r 读出指定文件

高级命令

命令 描述
x 交换模式空间与保持空间内容
d 删除当前模式空间内容,并进入下一个循环
D 删除多行模式空间中的首行,并进入下一个循环
n 读取匹配到的下一行至模式空间 [会覆盖模式空间原有的值]
N 读取匹配到的下一行至模式空间 [追加到原有内容后]
h 复制模式空间内容,到保持空间, 覆盖
H 复制模式空间内容,到保持空间, 追加
g 复制保持空间内容,到模式空间, 覆盖
G 复制保持空间内容,到模式空间, 追加
  • 模式空间(pattern space): 所有的处理动作都在这里,默认打印到终端
  • 保持空间(hold space): 数据暂存区域,类似中间变量
  • 循环标签
    • 格式: sed -n ‘:标签名 范围1 命令1; /模式/b 标签名’ filename
    • 调用: b, t, T

使用

  • 默认只替换在每行第一次出现目标文本
    1
    
    sed 's/root/ROOT/' /etc/passwd
    
  • 数字替换标记,替换每行的第二个 root 为 ROOT
    1
    
    sed 's/root/ROOT/2' /etc/passwd
    
  • g 替换标记,替换所有匹配的 root 为 ROOT
    1
    
    sed 's/root/ROOT/g' /etc/passwd
    
  • 替换每行第二次开始及之后的 root 为 ROOT
    1
    
    sed 's/root/ROOT/2g' /etc/passwd
    
  • 打印被替换过的行
    1
    
    sed -n 's/root/ROOT/gp' /etc/passwd
    
  • 把被替换过的行写入 change.txt 中
    1
    
    sed -n 's/root/ROOT/g w change.txt' /etc/passwd
    
  • 将第3行中所有的 bin 替换成 BIN
    1
    
    sed '3 s/bin/BIN/g' /etc/passwd
    
  • 将第2到5行中所有的 bin 替换成 BIN
    1
    
    sed '2,5 s/bin/BIN/g' /etc/passwd
    
  • 将第10行到最后一行中所有的 bin 替换成 BIN
    1
    
    sed '10,$ s/bin/BIN/g' /etc/passwd
    
  • 寻找包含有字符串 root 的行,并将匹配行的 bin 替换为 BIN
    1
    
    sed -n '/root/s/bin/BIN/p' /etc/passwd
    
  • 从匹配 root 的行开始替换 bin 为 BIN,直到匹配 nologin 的行,循环
    1
    
    sed -n '/root/,/nologin/s/bin/BIN/p' /etc/passwd
    
  • 删除匹配 root 的行
    1
    
    sed '/root/d' /etc/passwd
    
  • 删除第2到最后一行
    1
    
    sed '2,$d' /etc/passwd
    
  • 删除匹配 root 行及其下面两行
    1
    
    sed '/root/,+2d' /etc/passwd
    
  • 保留第四、五、六三行,其他行删除
    1
    
    sed '4,6!d' /etc/passwd
    
  • 每一行前面增加一个行 AAAA
    1
    
    sed 'iAAAA' /etc/passwd
    
  • 第一行前面增加一个行 AAAA
    1
    
    sed '1iAAAA' /etc/passwd
    
  • 第三行后面增加一个行 AAAA
    1
    
    sed '3aAAAA' /etc/passwd
    
  • 最后一行后面增加一个行 AAAA
    1
    
    sed '$aAAAA' /etc/passwd
    
  • 逐个字符替换
    1
    2
    
    echo abcdefggfedcba | sed 'y/acg/ACG/'
    # 输出 AbCdefGGfedCbA
    
  • 把第1行到第4行写入 test.txt
    1
    
    sed '1,4w test.txt' /etc/passwd
    
  • 把 test.txt 的内容插入第三行后
    1
    
    sed '3r test.txt' /etc/passwd
    
  • 把 000_00000000 换成 000.00000000
    1
    2
    3
    
    sed -i 's/\([0-9]\{3\}\)_\([0-9]\{8\}\)/\1.\2/g' phone_file
    # 或者
    sed -i -r 's/([0-9]{3})_([0-9]{8})/\1.\2/g' phone_file
    
  • 替换 root 为 (root)
    1
    
    sed -i 's/root/(&)/g' file_name
    
  • 把匹配 AAAA 行下的第二行中的 BBBB 改成 CCCC
    1
    
    sed -i '/AAAA/{n;n;s/BBBB/CCCC/g}' file_name
    
  • 在匹配 AAAA 行下的第三行下添加 CCCC 一行
    1
    
    sed -i '/AAAA/{n;n;n;s/$/\nCCCC/}' file_name
    

参考

mysql/mariadb 备份

xtrabackup

环境

  • mysql 8.4
  • rockylinux 9.6

安装

备份前准备工作

  • 备份目录如果是 nfs,挂载时需指定 sync 选项
  • 创建备份用户
    1
    2
    3
    4
    5
    
    CREATE USER xb@localhost IDENTIFIED BY 'Xtrabackup_1234';
    GRANT BACKUP_ADMIN, PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO xb@localhost;
    GRANT SELECT ON performance_schema.log_status TO xb@localhost;
    GRANT SELECT ON performance_schema.keyring_component_status TO xb@localhost;
    GRANT SELECT ON performance_schema.replication_group_members TO xb@localhost;
    

全量备份和恢复

  • 备份

Nfs 笔记

环境

  • 服务端 CentOS8 192.168.1.100
  • 客户端 CentOS8 192.168.1.101

服务端

  • 安装

    1
    2
    3
    4
    
    yum install nfs-utils
    systemctl enable nfs-server
    systemctl start nfs-server
    # rpcbind 服务自动 start 并 enable
    
  • 创建配置文件

    1
    2
    3
    4
    5
    
    mkdir /nfs_share -p
    chown -R nobody:nobody /nfs_share
    cat > /etc/exports <<EOF
    /nfs_share 192.168.1.0/24(rw,sync,all_squash)
    EOF
    
  • 重新载入配置

    1
    2
    3
    
    exportfs -r
    # 查看配置
    exportfs
    

客户端

  • 安装

CentOS7 安装 Postgresql

环境

  • CentOS 7
  • PostgreSQL 10.10

安装

  • 安装 yum 源
    1
    2
    3
    4
    5
    6
    7
    8
    
    yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
    # 或者从清华镜像站下载
    yum install https://mirrors.tuna.tsinghua.edu.cn/postgresql/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
    # 可以更换成清华镜像站地址
    sed -i 's,download.postgresql.org/pub,mirrors.tuna.tsinghua.edu.cn/postgresql,' /etc/yum.repos.d/pgdg-redhat-all.repo
    # 更新 yum 缓存
    yum clean all
    yum makecache fast
    
  • 安装 postgresql-server
    1
    
    yum install postgresql10-server
    
  • 初始化数据库
    1
    
    /usr/pgsql-10/bin/postgresql-10-setup initdb
    
  • 启动数据库
    1
    
    systemctl start postgresql-10
    

配置 postgresql.conf

  • 监听本机全部地址
    1
    
    clisten_addresses = '*'
    

配置 pg_hba.conf

  • 配置同网段客户端可通过 pguser1 使用密码登陆 pgdb1
    1
    
    echo 'host pgdb1 pguser1 samenet md5' >> pg_hba.conf
    
  • 配置任何客户端可通过任何用户使用密码登陆任何数据库
    1
    
    echo 'host all all all md5' >> pg_hba.conf
    

简单使用

  • 登陆数据库
    1
    2
    
    su - postgres
    psql -U postgres
    
  • 简单操作
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    -- 修改 postgres 用户的默认密码
    alter user postgres with password '123456';
    -- 创建新用户 pguser1
    create user pguser1 with password '123456';
    -- 创建数据库 pgdb1
    create database pgdb1 owner pguser1 encoding utf8;
    -- 授权
    grant all on database pgdb1 to pguser1;
    -- 查看系统操作帮助
    \?
    -- 查看 sql 语句操作帮助
    \h
    -- 查看建库语句操作
    \h create database
    -- 退出数据库
    \q
    

迁移数据库目录

  • 停止数据库 postgresql
    1
    
    systemctl stop postgresql-10
    
  • 移动数据库目录
    1
    2
    3
    
    mkdir -p /data/pgsql/10
    mv /var/lib/pgsql/10/data /data/pgsql/10/
    chown -R postgres.postgres /data/pgsql
    
  • 修改 service 文件
    1
    2
    
    sed -i 's,/var/lib/pgsql/10,/data/pgsql/10,' /usr/lib/systemd/system/postgresql-10.service
    systemctl daemon-reload
    
  • 启动数据库
    1
    
    systemctl start postgresql-10
    

awk 命令

格式

  • awk -F ‘分隔符正则’ -v 变量名=值 ‘BEGIN{动作} 条件{动作} END{动作}’ 文件1 文件2 …
  • awk -F ‘分隔符正则’ -f awk脚本文件名 文件1 文件2 …

常用内置变量

变量 说明
$0 当前记录
$1~$n 当前记录的第n个字段,字段间由FS分隔
FS 输入字段分隔符 默认是空格
NF 当前记录中的字段个数,就是有多少列
NR awk 开始执行程序后所读取的数据行数,就是行号,从1开始
RS 输入的记录他隔符默 认为换行符
OFS 输出字段分隔符 默认也是空格
ORS 输出的记录分隔符,默认为换行符
FNR 当前记录数,awk每打开一个新文件,FNR便从0重新累计
ARGC 命令行参数个数
ARGV 命令行参数字典,ARGV[0] 是 ‘awk’,ARGV[1] 是 FILENAME
FILENAME 当前输入文件的名字
IGNORECASE 如果为真,则进行忽略大小写的匹配
ENVIRON UNIX环境变量,如 ENVIRON[“PATH”]
FIELDWIDTHS 输入字段宽度的空白分隔字符串
OFMT 数字的输出格式(默认值是%.6g)
RSTART 被 match 匹配函数匹配的字符串位置
RLENGTH 被 match 匹配函数匹配的字符串长度

函数

常用内置函数

函数 说明
int(x) 返回 x 的整数部分
rand() 返回 0 到 1 之间的浮点数
gsub(Ere, “dest”, str) 把 str 中匹配扩展正则 Ere 的全部子串换成字符串 “dest”
sub(Ere, “dest”, str) 把 str 中匹配扩展正则 Ere 的第一个子串换成字符串 “dest”
substr(str, start, len) 返回 str 中从 start 开始(长度为 len )的子串
index(str1, str2) 返回 str1 中出现 str2 的位置,如果未找到,返回 0
length(str) 返回 str 的字符个数,如果未指定 str,返回 $0 包含字符个数
blength(str) 返回 str 的字节个数,如果未指定 str,返回 $0 包含字节个数
match(str, Ere) 返回 str 中匹配扩展正则 Ere 的位置,如果未找到,返回 0
split(str, arr, Ere) 把 str 按照扩展正则 Ere 切分成字典,存储到 arr 中,返回字典长度
tolower(str) 把 str 换成小写
toupper(str) 把 str 换成大写
sprintf("%s-%d", “abcd”, 1234) 返回 abcd-1234
strtonum(str) 返回十进制数字
delete arr[n] 删除字典/字典的对应元素
getline 读入当前行的下一行,重写变量 0
next 停止处理当前记录,开始处理下一行
nextfile 停止处理当前文件,开始处理下一个文件
system(shell-command) 返回命令退出状态
exit n 终止 awk,返回 n

自定义函数

  • 格式
    1
    2
    3
    4
    
    function fun_name(arg1, arg2, ...){
        #函数体
        return
    }
    

判断语句

  • if
    1
    2
    3
    4
    5
    6
    7
    
    if(条件){
        # 语句
    }else if(条件){
        # 语句
    }else{
        # 语句
    }
    

循环语句

  • for
    1
    2
    3
    4
    5
    6
    
    for(初始化;条件;变化){
        # 语句
    }
    for(变量 in 字典){
        # 语句
    }
    
  • while
    1
    2
    3
    
    while(条件){
        # 语句
    }
    
  • do while
    1
    2
    3
    
    do{
        # 语句
    }while(条件)
    
  • break 退出当前循环体
  • continue 退出本次循环,继续下一次循环

脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/usr/bin/awk -f

# 自定义的变量和函数
# ...

# 从这里开始执行
BEGIN{
    # 语句
}
条件{
    # 语句
}
END{
    # 语句
}

其他说明

  • 变量在使用时直接赋值即可,无需提前声明或定义
  • 个人认为,awk 没有数组只有字典,数组是键为整数的字典
  • 运算符(+, -, *, /, ++, – 等)和关系符操作(>, >=, <, <=, , ! 等)与 C 基本一致,也支持三目运算符(条件?值1:值2)
  • shell 中 awk 执行显式命令时,加载 shell 中的变量
    1
    2
    3
    4
    
    #!/bin/bash
    shell_value='abcd'
    echo | awk '{print "'$shell_value'"}'
    # 输出 abcd
    

参考