Linux

Linux 内核最初只是由芬兰人林纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的。 Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 UNIX 的多用户、多任务、支持多线程和多 CPU 的操作系统。 Linux 能运行主要的 UNIX 工具软件、应用程序和网络协议。它支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

Linux 基础

Linux 内核最初只是由芬兰人林纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的。 Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 UNIX 的多用户、多任务、支持多线程和多 CPU 的操作系统。 Linux 能运行主要的 UNIX 工具软件、应用程序和网络协议。它支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

Linux 基础

Bash 常用命令

基础常用命令

-rwxr-xr-x. 1 root root 4096 3月 26 10:57,其中最前面的 - 表示这是一个普通文件
lrwxrwxrwx. 1 root root 4096 3月 26 10:57,其中最前面的 l 表示这是一个链接文件,类似 Windows 的快捷方式
drwxr-xr-x. 5 root root 4096 3月 26 10:57,其中最前面的 d 表示这是一个目录
Linux 基础

CentOS 7 安装

概括

VMware 下安装 CentOS 过程

Linux 基础

Bash 其他常用命令

其他常用命令

资料

Linux 基础

Linux 介绍

Linux 这个名字

Linux 的 Wiki 介绍:http://zh.wikipedia.org/zh/Linux

Linux 也称:GNU/Linux,而其中 GNU 的全称又是:Gnu’s Not Unix

其中 GNU 放前面是有原因的,GNU 介绍:http://zh.wikipedia.org/wiki/GNU

对于 Linux 和 GNU/Linux 的两种叫法是有争议,可以看下面文章:https://zh.wikipedia.org/wiki/GNU/Linux命名爭議

其实我们可以认为:Linux 本质是指 Linux 内核,而称 GNU/Linux 则代表这是一个系统,所以我认为 Debian 的这个叫法是合理的,但是确实有点不好念和记忆。所以普遍大家直接称作 Linux。

通过上面的全称和资料其实我们也就了解到,Linux 本质来源不是 Unix,但是它借鉴了 Unix 的设计思想,所以在系统业界上把这种和 Unix 是一致设计思想的系统归为:类 Unix 系统

类 Unix 系统的介绍:https://zh.wikipedia.org/wiki/类Unix系统

类 Unix 系统,除了我们今天要讲的 Linux,还有大家熟知的 Mac OS X、FreeBSD(这两个是直接从 Unix 系发展过来的,所以相对 Linux 是比较地道的类 Unix 系统)

Linux 的发行版本

Linux 的 Wiki 中有这句话:

通常情况下,Linux 被打包成供个人计算机和服务器使用的 Linux 发行版,一些流行的主流 Linux 发布版,包括 Debian(及其派生版本 Ubuntu、Linux Mint)、Fedora(及其相关版本 Red Hat Enterprise Linux、CentOS)和 openSUSE、ArchLinux(这个是我补充的)等。

通过上面这句话我做了总结,我个人觉得应该这样分:

根据用途可以再总结:

其实 Linux 的发行版本有太多了,我也只是简单说下常见的而已,具体可以看:http://zh.wikipedia.org/wiki/Linux发行版列表

Linux 作用

为什么要用 Linux 系统?大家常看到的说法是这样的:

Linux 是一个开源的,有潜力,安全,免费的操作系统

我觉得这几个点都比较虚, 特别是免费这东西,在景德镇应该算是最不值钱的东西。作为系统的上层使用者来讲,我们之所以喜欢某个操作系统就是因为它可以加快的你生产效率,提高产能。我推荐 Linux 也只是因为它适合常见的编程语言做开发环境,仅此一点。

所有,对此我的总结就是:

如果你是某种语言的开发者,你从事这个行业,不管你怎么学习下去,Linux 永远绕不开。从简单的各种语言开发,到后期的服务器部署,分布式,集群环境,数据库相关等,Linux 都在等着你。如果你是新手程序员可能还不太懂我这句话,但是我这里可以这样提示:你可以认真去看下各个语言的官网、对应的开发组件官网,看下他们的下载和新手上路相关页面,都会有 Linux 系统对应的介绍,但是不一定有会 Windows。(P.S:微软系、美工等设计系是唯一这个总结之外的人)

在认识 Linux 作用上我以下面这边文章为结尾。Linux 和 Mac OS X 都是类 Unix 系统,所以这篇文章中基本上的理由都可以用到 Linux 上的。 为什么国外程序员爱用 Mac?http://www.vpsee.com/2009/06/why-programmers-love-mac/

推荐的发行版本

Ubuntu:适用于开发机

推荐版本:Ubuntu kylin 15.10

推荐理由:

我们是要在上面做开发的,不是要把他变成生活用机的,所以你认为自己尝试安装各种中文输入法很爽吗?自己尝试让国际 Ubuntu 版变成又一个符合国情的 kylin 很爽吗?真心别折腾这些没用的东西。就像我以前说的,大学老师让 Java 新手使用记事本写代码就是一种非常 shit 行为,不断地在 Windows 上用 cmd > javac 是毫无意义的。


CentOS:适用于服务器机

推荐版本:6.7

推荐理由:

Fedora(CentOS、RHEL) 系,是在国内外,作为企业服务器的系统最多,没有之一。我在 Quora 和知乎上也搜索了下,基本上大家都是赞同这个观点的。

Linux 应用

Linux 主要作为Linux发行版(通常被称为"distro")的一部分而使用。这些发行版由个人,松散组织的团队,以及商业机构和志愿者组织编写。它们通常包括了其他的系统软件和应用软件,以及一个用来简化系统初始安装的安装工具,和让软件安装升级的集成管理器。大多数系统还包括了像提供GUI界面的XFree86之类的曾经运行于BSD的程序。 一个典型的Linux发行版包括:Linux内核,一些GNU程序库和工具,命令行shell,图形界面的X Window系统和相应的桌面环境,如KDE或GNOME,并包含数千种从办公套件,编译器,文本编辑器到科学工具的应用软件。

Linux 应用

Zookeeper 安装

Docker 部署 Zookeeper

单个实例

单机多个实例(集群)

version: '3.1'

services:
  zoo1:
    image: zookeeper
    restart: always
    hostname: zoo1
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=0.0.0.0:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

  zoo2:
    image: zookeeper
    restart: always
    hostname: zoo2
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=0.0.0.0:2888:3888 server.3=zoo3:2888:3888

  zoo3:
    image: zookeeper
    restart: always
    hostname: zoo3
    ports:
      - 2183:2181
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=0.0.0.0:2888:3888

先安装 nc 再来校验 zookeeper 集群情况

校验

Zookeeper version: 3.4.11-37e277162d567b55a07d1755f0b31c32e93c01a0, built on 11/01/2017 18:06 GMT
Clients:
 /172.21.0.1:58872[0](queued=0,recved=1,sent=0)

Latency min/avg/max: 0/0/0
Received: 1
Sent: 0
Connections: 1
Outstanding: 0
Zxid: 0x100000000
Mode: follower
Node count: 4
Zookeeper version: 3.4.11-37e277162d567b55a07d1755f0b31c32e93c01a0, built on 11/01/2017 18:06 GMT
Clients:
 /172.21.0.1:36190[0](queued=0,recved=1,sent=0)

Latency min/avg/max: 0/0/0
Received: 1
Sent: 0
Connections: 1
Outstanding: 0
Zxid: 0x500000000
Mode: follower
Node count: 4
Zookeeper version: 3.4.11-37e277162d567b55a07d1755f0b31c32e93c01a0, built on 11/01/2017 18:06 GMT
Clients:
 /172.21.0.1:33344[0](queued=0,recved=1,sent=0)

Latency min/avg/max: 0/0/0
Received: 1
Sent: 0
Connections: 1
Outstanding: 0
Zxid: 0x500000000
Mode: leader
Node count: 4

多机多个实例(集群)

172.24.165.129 youmeekhost1
172.24.165.130 youmeekhost2
172.24.165.131 youmeekhost3
docker run -d \
-v /data/docker/zookeeper/data:/data \
-v /data/docker/zookeeper/log:/datalog \
-e ZOO_MY_ID=1 \
-e "ZOO_SERVERS=server.1=youmeekhost1:2888:3888 server.2=youmeekhost2:2888:3888 server.3=youmeekhost3:2888:3888" \
--name=zookeeper1 --net=host --restart=always zookeeper
docker run -d \
-v /data/docker/zookeeper/data:/data \
-v /data/docker/zookeeper/log:/datalog \
-e ZOO_MY_ID=2 \
-e "ZOO_SERVERS=server.1=youmeekhost1:2888:3888 server.2=youmeekhost2:2888:3888 server.3=youmeekhost3:2888:3888" \
--name=zookeeper2 --net=host --restart=always zookeeper
docker run -d \
-v /data/docker/zookeeper/data:/data \
-v /data/docker/zookeeper/log:/datalog \
-e ZOO_MY_ID=3 \
-e "ZOO_SERVERS=server.1=youmeekhost1:2888:3888 server.2=youmeekhost2:2888:3888 server.3=youmeekhost3:2888:3888" \
--name=zookeeper3 --net=host --restart=always zookeeper

需要环境

下载安装

集群环境搭建

确定机子环境

配置

server.1=192.168.1.121:2888:3888
server.2=192.168.1.111:2888:3888
server.3=192.168.1.112:2888:3888
Using config: /usr/program/zookeeper/zookeeper-3.4.8/bin/../conf/zoo.cfg
Mode: follower 或者 Mode: leader

Zookeeper 客户端工具

ZooInspector

zooweb

资料

Linux 应用

FTP(File Transfer Protocol)介绍

FTP 安装

FTP 使用之前要点

FTP 服务器配置文件常用参数

vsftpd 的两种传输模式

vsftpd 的两种运行模式

FTP 资料

Linux 应用

CI 一整套服务

环境说明

Gitlab + Redis + Postgresql

version: '2'

services:
  redis:
    restart: always
    image: sameersbn/redis:latest
    command:
    - --loglevel warning
    volumes:
    - /data/docker/gitlab/redis:/var/lib/redis:Z

  postgresql:
    restart: always
    image: sameersbn/postgresql:9.6-2
    volumes:
    - /data/docker/gitlab/postgresql:/var/lib/postgresql:Z
    environment:
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production
    - DB_EXTENSION=pg_trgm

  gitlab:
    restart: always
    image: sameersbn/gitlab:10.4.2-1
    depends_on:
    - redis
    - postgresql
    ports:
    - "10080:80"
    - "10022:22"
    volumes:
    - /data/docker/gitlab/gitlab:/home/git/data:Z
    environment:
    - DEBUG=false

    - DB_ADAPTER=postgresql
    - DB_HOST=postgresql
    - DB_PORT=5432
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production

    - REDIS_HOST=redis
    - REDIS_PORT=6379

    - TZ=Asia/Shanghai
    - GITLAB_TIMEZONE=Beijing

    - GITLAB_HTTPS=false
    - SSL_SELF_SIGNED=false

    - GITLAB_HOST=192.168.0.105
    - GITLAB_PORT=10080
    - GITLAB_SSH_PORT=10022
    - GITLAB_RELATIVE_URL_ROOT=
    - GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alphanumeric-string

    - GITLAB_ROOT_PASSWORD=
    - GITLAB_ROOT_EMAIL=

    - GITLAB_NOTIFY_ON_BROKEN_BUILDS=true
    - GITLAB_NOTIFY_PUSHER=false

    - GITLAB_EMAIL=notifications@example.com
    - GITLAB_EMAIL_REPLY_TO=noreply@example.com
    - GITLAB_INCOMING_EMAIL_ADDRESS=reply@example.com

    - GITLAB_BACKUP_SCHEDULE=daily
    - GITLAB_BACKUP_TIME=01:00

    - SMTP_ENABLED=false
    - SMTP_DOMAIN=www.example.com
    - SMTP_HOST=smtp.gmail.com
    - SMTP_PORT=587
    - SMTP_USER=mailer@example.com
    - SMTP_PASS=password
    - SMTP_STARTTLS=true
    - SMTP_AUTHENTICATION=login

    - IMAP_ENABLED=false
    - IMAP_HOST=imap.gmail.com
    - IMAP_PORT=993
    - IMAP_USER=mailer@example.com
    - IMAP_PASS=password
    - IMAP_SSL=true
    - IMAP_STARTTLS=false

    - OAUTH_ENABLED=false
    - OAUTH_AUTO_SIGN_IN_WITH_PROVIDER=
    - OAUTH_ALLOW_SSO=
    - OAUTH_BLOCK_AUTO_CREATED_USERS=true
    - OAUTH_AUTO_LINK_LDAP_USER=false
    - OAUTH_AUTO_LINK_SAML_USER=false
    - OAUTH_EXTERNAL_PROVIDERS=

    - OAUTH_CAS3_LABEL=cas3
    - OAUTH_CAS3_SERVER=
    - OAUTH_CAS3_DISABLE_SSL_VERIFICATION=false
    - OAUTH_CAS3_LOGIN_URL=/cas/login
    - OAUTH_CAS3_VALIDATE_URL=/cas/p3/serviceValidate
    - OAUTH_CAS3_LOGOUT_URL=/cas/logout

    - OAUTH_GOOGLE_API_KEY=
    - OAUTH_GOOGLE_APP_SECRET=
    - OAUTH_GOOGLE_RESTRICT_DOMAIN=

    - OAUTH_FACEBOOK_API_KEY=
    - OAUTH_FACEBOOK_APP_SECRET=

    - OAUTH_TWITTER_API_KEY=
    - OAUTH_TWITTER_APP_SECRET=

    - OAUTH_GITHUB_API_KEY=
    - OAUTH_GITHUB_APP_SECRET=
    - OAUTH_GITHUB_URL=
    - OAUTH_GITHUB_VERIFY_SSL=

    - OAUTH_GITLAB_API_KEY=
    - OAUTH_GITLAB_APP_SECRET=

    - OAUTH_BITBUCKET_API_KEY=
    - OAUTH_BITBUCKET_APP_SECRET=

    - OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL=
    - OAUTH_SAML_IDP_CERT_FINGERPRINT=
    - OAUTH_SAML_IDP_SSO_TARGET_URL=
    - OAUTH_SAML_ISSUER=
    - OAUTH_SAML_LABEL="Our SAML Provider"
    - OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:transient
    - OAUTH_SAML_GROUPS_ATTRIBUTE=
    - OAUTH_SAML_EXTERNAL_GROUPS=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_EMAIL=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_FIRST_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_LAST_NAME=

    - OAUTH_CROWD_SERVER_URL=
    - OAUTH_CROWD_APP_NAME=
    - OAUTH_CROWD_APP_PASSWORD=

    - OAUTH_AUTH0_CLIENT_ID=
    - OAUTH_AUTH0_CLIENT_SECRET=
    - OAUTH_AUTH0_DOMAIN=

    - OAUTH_AZURE_API_KEY=
    - OAUTH_AZURE_API_SECRET=
    - OAUTH_AZURE_TENANT_ID=

Nexus + Jenkins + SonarQube

version: '3'

networks:
  prodnetwork:
    driver: bridge

services:
  sonardb:
    image: postgres:9.6.6
    restart: always
    ports:
      - "5433:5432"
    networks:
      - prodnetwork
    volumes:
      - /data/docker/ci/postgresql:/var/lib/postgresql
    environment:
      - POSTGRES_USER=sonar
      - POSTGRES_PASSWORD=sonar
  sonar:
    image: sonarqube:6.7.1
    restart: always
    ports:
     - "19000:9000"
     - "19092:9092"
    networks:
      - prodnetwork
    depends_on:
      - sonardb
    volumes:
      - /data/docker/ci/sonarqube/conf:/opt/sonarqube/conf
      - /data/docker/ci/sonarqube/data:/opt/sonarqube/data
      - /data/docker/ci/sonarqube/extension:/opt/sonarqube/extensions
      - /data/docker/ci/sonarqube/bundled-plugins:/opt/sonarqube/lib/bundled-plugins
    environment:
      - SONARQUBE_JDBC_URL=jdbc:postgresql://sonardb:5432/sonar
      - SONARQUBE_JDBC_USERNAME=sonar
      - SONARQUBE_JDBC_PASSWORD=sonar
  nexus:
    image: sonatype/nexus3
    restart: always
    ports:
      - "18081:8081"
    networks:
      - prodnetwork
    volumes:
      - /data/docker/ci/nexus:/nexus-data
  jenkins:
    image: wine6823/jenkins:1.1
    restart: always
    ports:
      - "18080:8080"
    networks:
      - prodnetwork
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /usr/bin/docker:/usr/bin/docker
      - /etc/localtime:/etc/localtime:ro
      - $HOME/.ssh:/root/.ssh
      - /data/docker/ci/jenkins/lib:/var/lib/jenkins/
      - /data/docker/ci/jenkins/home:/var/jenkins_home
    depends_on:
      - nexus
      - sonar
    environment:
      - NEXUS_PORT=8081
      - SONAR_PORT=9000
      - SONAR_DB_PORT=5432

配置 Jenkins 拉取代码权限

Jenkins 特殊配置(减少权限问题,如果是内网的话)

配置 Gitlab Webhook

资料

Linux 应用

LDAP 安装和配置

LDAP 基本概念

LDAP 服务器端安装

设置OpenLDAP管理员密码

dn: olcDatabase={0}config,cn=config                                                                                            
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}YK8qBtlmEpjUiVEPyfmNNDALjBaUTasc

修改默认的domain

dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth"
  read by dn.base="cn=gitnavi,dc=youmeek,dc=com" read by * none

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=youmeek,dc=com

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=gitnavi,dc=youmeek,dc=com

dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}rNLkIMYKvYhbBjxLzSbjVsJnZSkrfC3w

dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by
  dn="cn=gitnavi,dc=youmeek,dc=com" write by anonymous auth by self write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=gitnavi,dc=youmeek,dc=com" write by * read

添加一个基本的目录

dn: dc=youmeek,dc=com
objectClass: top
objectClass: dcObject
objectclass: organization
o: youmeek dot Com
dc: youmeek

dn: cn=gitnavi,dc=youmeek,dc=com
objectClass: organizationalRole
cn: gitnavi
description: Directory Manager

dn: ou=People,dc=youmeek,dc=com
objectClass: organizationalUnit
ou: People

dn: ou=Group,dc=youmeek,dc=com
objectClass: organizationalUnit
ou: Group

测试连接

LDAP 客户端

资料

Linux 应用

Kubernets(K8S) 使用

环境说明

Kubernetes

安装准备 - Kubernetes 1.13 版本

开始安装 - Kubernetes 1.13.3 版本

安装具体流程

systemctl stop firewalld.service
systemctl disable firewalld.service
systemctl disable iptables.service

iptables -P FORWARD ACCEPT

setenforce 0 && sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

echo "vm.swappiness = 0" >> /etc/sysctl.conf
swapoff -a && sysctl -w vm.swappiness=0
hostnamectl --static set-hostname  k8s-master-1
hostnamectl --static set-hostname  k8s-node-1
hostnamectl --static set-hostname  k8s-node-2


vim /etc/hosts
192.168.0.127 k8s-master-1
192.168.0.128 k8s-node-1
192.168.0.129 k8s-node-2
ssh-keygen -t rsa

cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys


ssh localhost

ssh-copy-id -i ~/.ssh/id_rsa.pub -p 22 root@k8s-node-1(根据提示输入 k8s-node-1 密码)
ssh-copy-id -i ~/.ssh/id_rsa.pub -p 22 root@k8s-node-2(根据提示输入 k8s-node-2 密码)

ssh k8s-master-1
ssh k8s-node-1
ssh k8s-node-2
vim /etc/yum.repos.d/kubernetes.repo

[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg


scp -r /etc/yum.repos.d/kubernetes.repo root@k8s-node-1:/etc/yum.repos.d/
scp -r /etc/yum.repos.d/kubernetes.repo root@k8s-node-2:/etc/yum.repos.d/
mkdir -p /etc/cni/net.d && vim /etc/cni/net.d/10-flannel.conflist

{
    "name": "cbr0",
    "plugins": [
        {
            "type": "flannel",
            "delegate": {
                "hairpinMode": true,
                "isDefaultGateway": true
            }
        },
        {
            "type": "portmap",
            "capabilities": {
                "portMappings": true
            }
        }
    ]
}
vim /etc/sysctl.d/k8s.conf

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
vm.swappiness=0


scp -r /etc/sysctl.d/k8s.conf root@k8s-node-1:/etc/sysctl.d/
scp -r /etc/sysctl.d/k8s.conf root@k8s-node-2:/etc/sysctl.d/

modprobe br_netfilter && sysctl -p /etc/sysctl.d/k8s.conf
yum install -y kubelet-1.13.3 kubeadm-1.13.3 kubectl-1.13.3 --disableexcludes=kubernetes
vim  /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

最后一行添加:Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=cgroupfs"
systemctl enable kubelet && systemctl start kubelet

kubeadm version
kubectl version

echo 1 > /proc/sys/net/ipv4/ip_forward


kubeadm init \
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
--pod-network-cidr 10.244.0.0/16 \
--kubernetes-version 1.13.3 \
--ignore-preflight-errors=Swap

其中 10.244.0.0/16 是 flannel 插件固定使用的ip段,它的值取决于你准备安装哪个网络插件

这个过程会下载一些 docker 镜像,时间可能会比较久,看你网络情况。
终端会输出核心内容:
[init] Using Kubernetes version: v1.13.3
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Activating the kubelet service
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [k8s-master-1 localhost] and IPs [192.168.0.127 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [k8s-master-1 localhost] and IPs [192.168.0.127 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [k8s-master-1 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.0.127]
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 19.001686 seconds
[uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.13" in namespace kube-system with the configuration for the kubelets in the cluster
[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "k8s-master-1" as an annotation
[mark-control-plane] Marking the node k8s-master-1 as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node k8s-master-1 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: 8tpo9l.jlw135r8559kaad4
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstraptoken] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstraptoken] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstraptoken] creating the "cluster-info" ConfigMap in the "kube-public" namespace
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes master has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join 192.168.0.127:6443 --token 8tpo9l.jlw135r8559kaad4 --discovery-token-ca-cert-hash sha256:d6594ccc1310a45cbebc45f1c93f5ac113873786365ed63efcf667c952d7d197
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=$HOME/.kube/config
kubeadm token list

kubectl cluster-info
cd /opt && wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

kubectl apply -f /opt/kube-flannel.yml
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables

kubeadm join 192.168.0.127:6443 --token 8tpo9l.jlw135r8559kaad4 --discovery-token-ca-cert-hash sha256:d6594ccc1310a45cbebc45f1c93f5ac113873786365ed63efcf667c952d7d197

这时候终端会输出:

[preflight] Running pre-flight checks
[discovery] Trying to connect to API Server "192.168.0.127:6443"
[discovery] Created cluster-info discovery client, requesting info from "https://192.168.0.127:6443"
[discovery] Requesting info from "https://192.168.0.127:6443" again to validate TLS against the pinned public key
[discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "192.168.0.127:6443"
[discovery] Successfully established connection with API Server "192.168.0.127:6443"
[join] Reading configuration from the cluster...
[join] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.13" ConfigMap in the kube-system namespace
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Activating the kubelet service
[tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap...
[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "k8s-node-1" as an annotation

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the master to see this node join the cluster.
NAME                 STATUS    MESSAGE              ERROR
controller-manager   Healthy   ok
scheduler            Healthy   ok
etcd-0               Healthy   {"health": "true"} 
结果都是 Healthy 则表示可以了,不然就得检查。必要时可以用:`kubeadm reset` 重置,重新进行集群初始化
如果还是 NotReady,则查看错误信息:kubectl get pods --all-namespaces
其中:Pending/ContainerCreating/ImagePullBackOff 都是 Pod 没有就绪,我们可以这样查看对应 Pod 遇到了什么问题
kubectl describe pod <Pod Name> --namespace=kube-system
或者:kubectl logs <Pod Name> -n kube-system
tail -f /var/log/messages

主要概念

创建,调度以及管理的最小单元
共存的一组容器的集合
容器共享PID,网络,IPC以及UTS命名空间
容器共享存储卷
短暂存在
数据持久化
Pod中容器共享数据
生命周期
支持多种类型的数据卷 – emptyDir, hostpath, gcePersistentDisk, awsElasticBlockStore, nfs, iscsi, glusterfs, secrets
用以标示对象(如Pod)的key/value对
组织并选择对象子集
确保在任一时刻运行指定数目的Pod
容器重新调度
规模调整
在线升级
多发布版本跟踪
抽象一系列Pod并定义其访问规则
固定IP地址和DNS域名
通过环境变量和DNS发现服务
负载均衡
外部服务 – ClusterIP, NodePort, LoadBalancer

主要组成模块

高可用的Key/Value存储
只有apiserver有读写权限
使用etcd集群确保数据可靠性
Kubernetes系统入口, REST
认证
授权
访问控制
服务帐号
资源限制
资源需求
服务需求
硬件/软件/策略限制
关联性和非关联性
数据本地化
Replication controller
Endpoint controller
Namespace controller
Serviceaccount controller
节点管理器
确保调度到本节点的Pod的运行和健康
Pod网络代理
TCP/UDP请求转发
负载均衡(Round Robin)
环境变量
DNS – kube2sky, etcd,skydns
容器间互相通信
节点和容器间互相通信
每个Pod使用一个全局唯一的IP
kubelet保证每一个master节点的服务正常运行
系统监控程序确保kubelet正常运行
Etcd集群
多个apiserver进行负载均衡
Master选举确保kube-scheduler和kube-controller-manager高可用

资料

Linux 应用

Hadoop 安装和配置

Hadoop 说明

基础环境

集群环境设置

hostnamectl --static set-hostname linux01
hostnamectl --static set-hostname linux02
hostnamectl --static set-hostname linux03
就按这个来,其他多余的别加,不然可能也会有影响
vim /etc/hosts
172.16.0.17 linux01
172.16.0.43 linux02
172.16.0.180 linux03
生产密钥对
ssh-keygen -t rsa


公钥内容写入 authorized_keys
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys

测试:
ssh localhost

ssh-copy-id -i ~/.ssh/id_rsa.pub -p 22 root@172.16.0.43,根据提示输入 linux02 机器的 root 密码,成功会有相应提示
ssh-copy-id -i ~/.ssh/id_rsa.pub -p 22 root@172.16.0.180,根据提示输入 linux03 机器的 root 密码,成功会有相应提示


在 linux01 上测试:
ssh linux02
ssh linux03

Hadoop 安装

mkdir -p /data/hadoop/hdfs/name /data/hadoop/hdfs/data /data/hadoop/hdfs/tmp
cd /usr/local && wget http://apache.claz.org/hadoop/common/hadoop-2.6.5/hadoop-2.6.5.tar.gz
tar zxvf hadoop-2.6.5.tar.gz,有 191M 左右
vim /etc/profile

export HADOOP_HOME=/usr/local/hadoop-2.6.5
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

source /etc/profile

修改 linux01 配置

修改 JAVA_HOME
vim $HADOOP_HOME/etc/hadoop/hadoop-env.sh

把 25 行的
export JAVA_HOME=${JAVA_HOME}
都改为
export JAVA_HOME=/usr/local/jdk1.8.0_191


vim $HADOOP_HOME/etc/hadoop/yarn-env.sh

文件开头加一行 export JAVA_HOME=/usr/local/jdk1.8.0_191


vim $HADOOP_HOME/etc/hadoop/core-site.xml,改为:

<configuration>
    <property>
        <name>hadoop.tmp.dir</name>
        <value>file:/data/hadoop/hdfs/tmp</value>
    </property>
    <property>
        <name>io.file.buffer.size</name>
        <value>131072</value>
    </property>
    <!--
    <property>
        <name>fs.default.name</name>
        <value>hdfs://linux01:9000</value>
    </property>
    -->
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://linux01:9000</value>
    </property>
    <property>
        <name>hadoop.proxyuser.root.hosts</name>
        <value>*</value>
    </property>
    <property>
        <name>hadoop.proxyuser.root.groups</name>
        <value>*</value>
    </property>
</configuration>
vim $HADOOP_HOME/etc/hadoop/hdfs-site.xml 

<configuration>
  <property>
    <name>dfs.replication</name>
    <value>2</value>
  </property>
  <property>
    <name>dfs.namenode.name.dir</name>
    <value>file:/data/hadoop/hdfs/name</value>
    <final>true</final>
  </property>
  <property>
    <name>dfs.datanode.data.dir</name>
    <value>file:/data/hadoop/hdfs/data</value>
    <final>true</final>
  </property>
  <property>
    <name>dfs.webhdfs.enabled</name>
    <value>true</value>
  </property>
  <property>
    <name>dfs.permissions</name>
    <value>false</value>
  </property>
</configuration>

新创建:vim $HADOOP_HOME/etc/hadoop/mapred-site.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <property>
    <name>mapreduce.framework.name</name>
    <value>yarn</value>
  </property>
    
  <property>
    <name>mapreduce.map.memory.mb</name>
    <value>4096</value>
  </property>
  
  <property>
    <name>mapreduce.reduce.memory.mb</name>
    <value>8192</value>
  </property>
  
  <property>
    <name>mapreduce.map.java.opts</name>
    <value>-Xmx3072m</value>
  </property>
  
  <property>
    <name>mapreduce.reduce.java.opts</name>
    <value>-Xmx6144m</value>
  </property>  
  
</configuration>
vim $HADOOP_HOME/etc/hadoop/yarn-site.xml 


<configuration>
  <property>
    <name>yarn.resourcemanager.hostname</name>
    <value>linux01</value>
  </property>

  <property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
  </property>

  <property>
    <name>yarn.nodemanager.vmem-pmem-ratio</name>
    <value>2.1</value>
  </property>
  
  <property>
    <name>yarn.nodemanager.resource.memory-mb</name>
    <value>20480</value>
  </property>
  
  <property>
    <name>yarn.scheduler.minimum-allocation-mb</name>
    <value>2048</value>
  </property>

</configuration>
vim $HADOOP_HOME/etc/hadoop/slaves

把默认的配置里面的 localhost 删除,换成:
linux02
linux03

scp -r /usr/local/hadoop-2.6.5 root@linux02:/usr/local/

scp -r /usr/local/hadoop-2.6.5 root@linux03:/usr/local/

linux01 机子运行

格式化  HDFS
hdfs namenode -format

[root@linux01 hadoop-2.6.5]# hdfs namenode -format
18/12/17 17:47:17 INFO namenode.NameNode: STARTUP_MSG:
/************************************************************
STARTUP_MSG: Starting NameNode
STARTUP_MSG:   host = localhost/127.0.0.1
STARTUP_MSG:   args = [-format]
STARTUP_MSG:   version = 2.6.5
STARTUP_MSG:   classpath = /usr/local/hadoop-2.6.5/etc/hadoop:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/apacheds-kerberos-codec-2.0.0-M15.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-io-2.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/activation-1.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/netty-3.6.2.Final.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jackson-mapper-asl-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/slf4j-api-1.7.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/junit-4.11.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/curator-recipes-2.6.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jasper-compiler-5.5.23.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jets3t-0.9.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-lang-2.6.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-digester-1.8.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jackson-core-asl-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/apacheds-i18n-2.0.0-M15.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/guava-11.0.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/gson-2.2.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jackson-jaxrs-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jettison-1.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jetty-6.1.26.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/api-util-1.0.0-M20.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/log4j-1.2.17.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-beanutils-core-1.8.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-httpclient-3.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-el-1.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/paranamer-2.3.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/slf4j-log4j12-1.7.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-collections-3.2.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jersey-server-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-net-3.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/hadoop-auth-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jasper-runtime-5.5.23.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jaxb-impl-2.2.3-1.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/hamcrest-core-1.3.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/stax-api-1.0-2.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-beanutils-1.7.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/protobuf-java-2.5.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/curator-framework-2.6.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/xz-1.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jsr305-1.3.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jsp-api-2.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-compress-1.4.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/asm-3.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jsch-0.1.42.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-configuration-1.6.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-cli-1.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jackson-xc-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-logging-1.1.3.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/htrace-core-3.0.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jetty-util-6.1.26.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-math3-3.1.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/mockito-all-1.8.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jersey-json-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/zookeeper-3.4.6.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/httpclient-4.2.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/servlet-api-2.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/xmlenc-0.52.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/httpcore-4.2.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/api-asn1-api-1.0.0-M20.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/java-xmlbuilder-0.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/avro-1.7.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jaxb-api-2.2.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/commons-codec-1.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/jersey-core-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/snappy-java-1.0.4.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/curator-client-2.6.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/hadoop-annotations-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/hadoop-common-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/hadoop-common-2.6.5-tests.jar:/usr/local/hadoop-2.6.5/share/hadoop/common/hadoop-nfs-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/commons-io-2.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/netty-3.6.2.Final.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/jackson-mapper-asl-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/commons-lang-2.6.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/commons-daemon-1.0.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/jackson-core-asl-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/guava-11.0.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/jetty-6.1.26.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/log4j-1.2.17.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/commons-el-1.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/xercesImpl-2.9.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/jersey-server-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/jasper-runtime-5.5.23.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/protobuf-java-2.5.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/jsr305-1.3.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/xml-apis-1.3.04.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/jsp-api-2.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/asm-3.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/commons-cli-1.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/commons-logging-1.1.3.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/htrace-core-3.0.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/jetty-util-6.1.26.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/servlet-api-2.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/xmlenc-0.52.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/commons-codec-1.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/lib/jersey-core-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/hadoop-hdfs-2.6.5-tests.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/hadoop-hdfs-nfs-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/hdfs/hadoop-hdfs-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/commons-io-2.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/activation-1.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/aopalliance-1.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/netty-3.6.2.Final.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jackson-mapper-asl-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/commons-lang-2.6.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jackson-core-asl-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/guice-3.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/guava-11.0.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jackson-jaxrs-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jettison-1.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jetty-6.1.26.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/log4j-1.2.17.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/commons-httpclient-3.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/commons-collections-3.2.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jersey-server-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jaxb-impl-2.2.3-1.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/stax-api-1.0-2.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/protobuf-java-2.5.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/xz-1.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jsr305-1.3.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jersey-client-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/guice-servlet-3.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/commons-compress-1.4.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/asm-3.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/commons-cli-1.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jersey-guice-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jackson-xc-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/commons-logging-1.1.3.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jetty-util-6.1.26.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/leveldbjni-all-1.8.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jersey-json-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/javax.inject-1.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/zookeeper-3.4.6.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/servlet-api-2.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jaxb-api-2.2.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jline-0.9.94.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/commons-codec-1.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/lib/jersey-core-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-server-web-proxy-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-api-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-server-common-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-registry-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-server-nodemanager-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-client-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-common-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-applications-unmanaged-am-launcher-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-server-tests-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-server-resourcemanager-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-server-applicationhistoryservice-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/yarn/hadoop-yarn-applications-distributedshell-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/commons-io-2.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/aopalliance-1.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/netty-3.6.2.Final.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/jackson-mapper-asl-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/junit-4.11.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/jackson-core-asl-1.9.13.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/guice-3.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/log4j-1.2.17.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/paranamer-2.3.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/jersey-server-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/hamcrest-core-1.3.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/protobuf-java-2.5.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/xz-1.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/guice-servlet-3.0.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/commons-compress-1.4.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/asm-3.2.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/jersey-guice-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/leveldbjni-all-1.8.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/javax.inject-1.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/avro-1.7.4.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/jersey-core-1.9.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/snappy-java-1.0.4.1.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/lib/hadoop-annotations-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/hadoop-mapreduce-client-app-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/hadoop-mapreduce-client-common-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/hadoop-mapreduce-client-shuffle-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/hadoop-mapreduce-client-core-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/hadoop-mapreduce-client-hs-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/hadoop-mapreduce-client-hs-plugins-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.5.jar:/usr/local/hadoop-2.6.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.6.5-tests.jar:/usr/local/hadoop-2.6.5/contrib/capacity-scheduler/*.jar
STARTUP_MSG:   build = https://github.com/apache/hadoop.git -r e8c9fe0b4c252caf2ebf1464220599650f119997; compiled by 'sjlee' on 2016-10-02T23:43Z
STARTUP_MSG:   java = 1.8.0_191
************************************************************/
18/12/17 17:47:17 INFO namenode.NameNode: registered UNIX signal handlers for [TERM, HUP, INT]
18/12/17 17:47:17 INFO namenode.NameNode: createNameNode [-format]
Formatting using clusterid: CID-beba43b4-0881-48b4-8eda-5c3bca046398
18/12/17 17:47:17 INFO namenode.FSNamesystem: No KeyProvider found.
18/12/17 17:47:17 INFO namenode.FSNamesystem: fsLock is fair:true
18/12/17 17:47:17 INFO blockmanagement.DatanodeManager: dfs.block.invalidate.limit=1000
18/12/17 17:47:17 INFO blockmanagement.DatanodeManager: dfs.namenode.datanode.registration.ip-hostname-check=true
18/12/17 17:47:17 INFO blockmanagement.BlockManager: dfs.namenode.startup.delay.block.deletion.sec is set to 000:00:00:00.000
18/12/17 17:47:17 INFO blockmanagement.BlockManager: The block deletion will start around 2018 Dec 17 17:47:17
18/12/17 17:47:17 INFO util.GSet: Computing capacity for map BlocksMap
18/12/17 17:47:17 INFO util.GSet: VM type       = 64-bit
18/12/17 17:47:17 INFO util.GSet: 2.0% max memory 889 MB = 17.8 MB
18/12/17 17:47:17 INFO util.GSet: capacity      = 2^21 = 2097152 entries
18/12/17 17:47:17 INFO blockmanagement.BlockManager: dfs.block.access.token.enable=false
18/12/17 17:47:17 INFO blockmanagement.BlockManager: defaultReplication         = 2
18/12/17 17:47:17 INFO blockmanagement.BlockManager: maxReplication             = 512
18/12/17 17:47:17 INFO blockmanagement.BlockManager: minReplication             = 1
18/12/17 17:47:17 INFO blockmanagement.BlockManager: maxReplicationStreams      = 2
18/12/17 17:47:17 INFO blockmanagement.BlockManager: replicationRecheckInterval = 3000
18/12/17 17:47:17 INFO blockmanagement.BlockManager: encryptDataTransfer        = false
18/12/17 17:47:17 INFO blockmanagement.BlockManager: maxNumBlocksToLog          = 1000
18/12/17 17:47:17 INFO namenode.FSNamesystem: fsOwner             = root (auth:SIMPLE)
18/12/17 17:47:17 INFO namenode.FSNamesystem: supergroup          = supergroup
18/12/17 17:47:17 INFO namenode.FSNamesystem: isPermissionEnabled = false
18/12/17 17:47:17 INFO namenode.FSNamesystem: HA Enabled: false
18/12/17 17:47:17 INFO namenode.FSNamesystem: Append Enabled: true
18/12/17 17:47:17 INFO util.GSet: Computing capacity for map INodeMap
18/12/17 17:47:17 INFO util.GSet: VM type       = 64-bit
18/12/17 17:47:17 INFO util.GSet: 1.0% max memory 889 MB = 8.9 MB
18/12/17 17:47:17 INFO util.GSet: capacity      = 2^20 = 1048576 entries
18/12/17 17:47:17 INFO namenode.NameNode: Caching file names occuring more than 10 times
18/12/17 17:47:17 INFO util.GSet: Computing capacity for map cachedBlocks
18/12/17 17:47:17 INFO util.GSet: VM type       = 64-bit
18/12/17 17:47:17 INFO util.GSet: 0.25% max memory 889 MB = 2.2 MB
18/12/17 17:47:17 INFO util.GSet: capacity      = 2^18 = 262144 entries
18/12/17 17:47:17 INFO namenode.FSNamesystem: dfs.namenode.safemode.threshold-pct = 0.9990000128746033
18/12/17 17:47:17 INFO namenode.FSNamesystem: dfs.namenode.safemode.min.datanodes = 0
18/12/17 17:47:17 INFO namenode.FSNamesystem: dfs.namenode.safemode.extension     = 30000
18/12/17 17:47:17 INFO namenode.FSNamesystem: Retry cache on namenode is enabled
18/12/17 17:47:17 INFO namenode.FSNamesystem: Retry cache will use 0.03 of total heap and retry cache entry expiry time is 600000 millis
18/12/17 17:47:17 INFO util.GSet: Computing capacity for map NameNodeRetryCache
18/12/17 17:47:17 INFO util.GSet: VM type       = 64-bit
18/12/17 17:47:17 INFO util.GSet: 0.029999999329447746% max memory 889 MB = 273.1 KB
18/12/17 17:47:17 INFO util.GSet: capacity      = 2^15 = 32768 entries
18/12/17 17:47:17 INFO namenode.NNConf: ACLs enabled? false
18/12/17 17:47:17 INFO namenode.NNConf: XAttrs enabled? true
18/12/17 17:47:17 INFO namenode.NNConf: Maximum size of an xattr: 16384
18/12/17 17:47:17 INFO namenode.FSImage: Allocated new BlockPoolId: BP-233285725-127.0.0.1-1545040037972
18/12/17 17:47:18 INFO common.Storage: Storage directory /data/hadoop/hdfs/name has been successfully formatted.
18/12/17 17:47:18 INFO namenode.FSImageFormatProtobuf: Saving image file /data/hadoop/hdfs/name/current/fsimage.ckpt_0000000000000000000 using no compression
18/12/17 17:47:18 INFO namenode.FSImageFormatProtobuf: Image file /data/hadoop/hdfs/name/current/fsimage.ckpt_0000000000000000000 of size 321 bytes saved in 0 seconds.
18/12/17 17:47:18 INFO namenode.NNStorageRetentionManager: Going to retain 1 images with txid >= 0
18/12/17 17:47:18 INFO util.ExitUtil: Exiting with status 0
18/12/17 17:47:18 INFO namenode.NameNode: SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at localhost/127.0.0.1
************************************************************/

HDFS 启动

这个命令效果:
主节点会启动任务:NameNode 和 SecondaryNameNode
从节点会启动任务:DataNode


主节点查看:jps,可以看到:
21922 Jps
21603 NameNode
21787 SecondaryNameNode


从节点查看:jps 可以看到:
19728 DataNode
19819 Jps
Configured Capacity: 0 (0 B)
Present Capacity: 0 (0 B)
DFS Remaining: 0 (0 B)
DFS Used: 0 (0 B)
DFS Used%: NaN%
Under replicated blocks: 0
Blocks with corrupt replicas: 0
Missing blocks: 0

YARN 运行

start-yarn.sh
然后 jps 你会看到一个:ResourceManager 

从节点你会看到:NodeManager

停止:stop-yarn.sh

端口情况

tcp        0      0 172.16.0.17:9000        0.0.0.0:*               LISTEN      22932/java >> NameNode
tcp        0      0 0.0.0.0:50070           0.0.0.0:*               LISTEN      22932/java >> NameNode
tcp        0      0 0.0.0.0:50090           0.0.0.0:*               LISTEN      23125/java >> SecondaryNameNode
tcp6       0      0 172.16.0.17:8030      :::*                    LISTEN      23462/java   >> ResourceManager
tcp6       0      0 172.16.0.17:8031      :::*                    LISTEN      23462/java   >> ResourceManager
tcp6       0      0 172.16.0.17:8032      :::*                    LISTEN      23462/java   >> ResourceManager
tcp6       0      0 172.16.0.17:8033      :::*                    LISTEN      23462/java   >> ResourceManager
tcp6       0      0 172.16.0.17:8088      :::*                    LISTEN      23462/java   >> ResourceManager
tcp        0      0 0.0.0.0:50010           0.0.0.0:*               LISTEN      14545/java >> DataNode
tcp        0      0 0.0.0.0:50020           0.0.0.0:*               LISTEN      14545/java >> DataNode
tcp        0      0 0.0.0.0:50075           0.0.0.0:*               LISTEN      14545/java >> DataNode
tcp6       0      0 :::8040                 :::*                    LISTEN      14698/java >> NodeManager
tcp6       0      0 :::8042                 :::*                    LISTEN      14698/java >> NodeManager
tcp6       0      0 :::13562                :::*                    LISTEN      14698/java >> NodeManager
tcp6       0      0 :::37481                :::*                    LISTEN      14698/java >> NodeManager

管理界面


运行作业


资料

Linux 应用

Gitlab 安装和配置

Docker Compose 安装方式

gitlab:
  image: sameersbn/gitlab:10.4.2-1
  ports:
    - "10022:22"
    - "10080:80"
  links:
    - gitlab-redis:redisio
    - gitlab-postgresql:postgresql
  environment:
    - GITLAB_PORT=80
    - GITLAB_SSH_PORT=22
    - GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alpha-numeric-string
    - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alpha-numeric-string
    - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alpha-numeric-string
  volumes:
    - /data/docker/gitlab/gitlab:/home/git/data
  restart: always
gitlab-redis:
  image: sameersbn/redis
  volumes:
    - /data/docker/gitlab/redis:/var/lib/redis
  restart: always
gitlab-postgresql:
  image: sameersbn/postgresql:9.6-2
  environment:
    - DB_NAME=gitlabhq_production
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_EXTENSION=pg_trgm
  volumes:
    - /data/docker/gitlab/postgresql:/var/lib/postgresql
  restart: always

Gitlab 高可用方案(High Availability)

原始安装方式(推荐)

sudo yum install -y curl policycoreutils-python openssh-server

sudo systemctl enable sshd
sudo systemctl start sshd

curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash
sudo EXTERNAL_URL="http://192.168.1.123:8181" yum install -y gitlab-ce

配置

配置 Jenkins 拉取代码权限

权限

用户组的权限

行为 Guest Reporter Developer Master Owner
浏览组
编辑组
创建项目
管理组成员
移除组

项目组的权限

行为 Guest Reporter Developer Master Owner
创建issue
留言评论
更新代码
下载工程
创建代码片段
创建合并请求
创建新分支
提交代码到非保护分支
强制提交到非保护分支
移除非保护分支
添加tag
创建wiki
管理issue处理者
管理labels
创建里程碑
添加项目成员
提交保护分支
使能分支保护
修改/移除tag
编辑工程
添加deploy keys
配置hooks
切换visibility level
切换工程namespace
移除工程
强制提交保护分支
移除保护分支

批量从一个项目中的成员转移到另外一个项目

限定哪些分支可以提交、可以 merge

Gitlab 的其他功能使用

创建用户

创建群组

创建项目

增加 SSH keys

使用 Gitlab 的一个开发流程 - Git flow

接入第三方登录

gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_allow_single_sign_on'] = ['google_oauth2', 'facebook', 'twitter', 'oauth2_generic']
gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_sync_profile_attributes'] = ['email','username']
gitlab_rails['omniauth_external_providers'] = ['google_oauth2', 'facebook', 'twitter', 'oauth2_generic']
gitlab_rails['omniauth_providers'] = [
    {
        "name"=> "google_oauth2",
        "label"=> "Google",
        "app_id"=> "123456",
        "app_secret"=> "123456",
        "args"=> {
            "access_type"=> 'offline',
            "approval_prompt"=> '123456'
        }
    },
    {
        "name"=> "facebook",
        "label"=> "facebook",
        "app_id"=> "123456",
        "app_secret"=> "123456"
    },
    {
        "name"=> "twitter",
        "label"=> "twitter",
        "app_id"=> "123456",
        "app_secret"=> "123456"
    },
    {
        "name" => "oauth2_generic",
        "app_id" => "123456",
        "app_secret" => "123456",
        "args" => {
          client_options: {
            "site" => "http://sso.cdk8s.com:9090/sso",
            "user_info_url" => "/oauth/userinfo"
          },
          user_response_structure: {
            root_path: ["user_attribute"],
            attributes: { 
              "nickname": "username" 
            }
          }
        }
    }
]

资料

Linux 应用

Rinetd:一个用户端口重定向工具

Rinetd:一个用户端口重定向工具

概述

Rinetd 是一个 TCP 连接重定向工具,当我们需要进行流量的代理转发的时候,我们可以通过该工具完成。Rinetd 是一个使用异步 IO 的单进程的服务,它可以处理配置在 /etc/rinetd.conf 中的任意数量的连接,但是并不会过多的消耗服务器的资源。Rinetd 不能用于重定向 FTP 服务,因为 FTP 服务使用了多个 socket 进行通讯。

如果需要 Rinetd 随系统启动一起启动,可以在 /etc/rc.local 中添加启动命令 /usr/sbin/rinetd。在没有使用 -c 选项指定其他配置文件的情况下,Rinetd 使用默认的配置文件 /etc/rinetd.conf

快速使用

git clone https://github.com/boutell/rinetd.git
cd rinetd
make && make install
echo "0.0.0.0 8080 www.baidu.com 80" > /etc/rinetd.conf
rinetd -c /etc/rinetd.conf

这里所有对 Rinetd 宿主机 8080 端口的请求都会被转发到 Baidu 上,注意: 保指定的端口没有被其他应用占用,如上面的 8080 端口。使用 kill -1 信号可以使 Rinetd 重新加载配置信息而不中断现有的连接。

转发规则

Rinetd 的大部分配置都是配置转发规则,规则如下:

bindaddress bindport connectaddress connectport
源地址       源端口     目的地址      目的端口

这里的地址可以是主机名也可以是 IP 地址。

如要将对 192.1.1.10:8080 的请求代理到 http://www.example.com:80 上,参照上面的规则配置如下:

www.example.com 80 192.1.1.10:8080

这里将对外的服务地址 http://www.example.com 重定向到了内部地址 192.1.1.10 的 8080 端口上。通常 192.1.1.10:8080 在防火墙的内部,外部请求并不能直接访问。如果我们源地址使用 IP 地址 0.0.0.0 ,那么代表将该服务器所有 IP 地址对应端口上的请求都代理到目的地址上。

权限控制

Rinetd 使用 allow patterndeny pattern 两个关键字进行访问权限的控制。如:

allow 192.1.5.*
deny 192.1.5.1

这里 pattern 的内容必须是一个 IP 地址,不能是主机名或者域名。可以使用 ? 匹配 0 - 9 的任意一个字符,使用 * 匹配 0 -9 的任意个的字符。在转发规则之前配置的权限规则会作为一个全局生效的规则生效,在转发规则之后配置的权限规则仅适用于本条转发规则。校验的过程是先校验是否能够通过全局规则,再校验特定的规则。

日志收集

Rinetd 可以产生使用制表符分隔的日志或者 Web 服务器下的通用日志格式。默认情况下,Rinetd 不产生日志,如果需要获取日志,需要添加配置:

logfile /var/log/rinetd.log

如果需要采集 Web 通用格式的日志,需要添加配置:

gcommon

Linux 实践

Unix 特点:多用户多任务;命令行界面;简单、通用、高效; Linux 是一个多用户多任务的操作系统,也是一款自由软件,拥有良好的用户界面, 支持多种处理器架构,移植方便。 严格的来讲,Linux 并不算是一个操作系统,只是一个 Linux 系统中的内核,即计算 机软件与硬件通讯之间的平台; Linux的全称是GNU/Linux,这才算是一个真正意义上的Linux系统。 设计原则:1)所有的东西都是文件,所以管理简单                   2)所有操作系统配置数据都存储在正文文件中                   3)每个操作系统命令或应用程序很小,只完成单一功能                   4)避免使用俘获用户的接口,很少交互命令,应用程序由vi编辑器等完成交互                   5)多个程序串接在一起完成复杂任务

Linux 实践

Error: ENOSPC: System limit for number of file watchers reached

在使用Ubuntu进行开发时,会遇到这个错误!

Error: ENOSPC: System limit for number of file watchers reached,

这个错误的意思时系统对文件监控的数量已经到达限制数量了!!

造成的结果: 执行的命令失败!或抛出警告(比如执行 react-native start 或者打开 vsocde)

解决方法:

修改系统监控文件数量

Ubuntu

sudo vim /etc/sysctl.conf

添加一行在最下面

fs.inotify.max_user_watches = 524288

执行

sudo sysctl -p

参考:

https://blog.csdn.net/weixin_30640291/article/details/94920800

https://www.cnblogs.com/or2-/p/10461045.html

https://www.jianshu.com/p/4d2edd55b471

https://blog.csdn.net/weixin_43760383/article/details/84326032

Linux 实践

使用Nginx转发TCP/UDP

使用Nginx转发TCP/UDP

环境

编译安装Nginx

从1.9.0开始,nginx就支持对TCP的转发,而到了1.9.13时,UDP转发也支持了。提供此功能的模块为ngx_stream_core。不过Nginx默认没有开启此模块,所以需要手动安装。

# http://nginx.org/download/
cd /usr/local/src
wget http://nginx.org/download/nginx-1.19.2.tar.gz
tar zxf nginx-1.19.2.tar.gz
cd nginx-1.19.2
./configure --prefix=/usr/local/nginx --with-stream --without-http
make && make install

Note:由于是传输层转发,本着最小化原则,就关闭了http功能。

配置Nginx

TCP转发

目标:通过3000端口访问本机Mysql(其中mysql使用yum安装,默认配置文件)

/usr/local/nginx/conf/nginx.conf配置如下:

user nobody;
worker_processes  auto;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    use epoll;
    worker_connections  1024;
}


stream {
    server {
        listen 3000;
        proxy_pass 127.0.0.1:3306;

    # 也支持socket
    # proxy_pass unix:/var/lib/mysql/mysql.socket;
    }
}

首先,先通过3306端口访问mysql:

然后,启动Nginx:

最后使用3000端口访问mysql:

UDP转发

目标: 发送UDP数据到3000端口,3001端口可以接收

/usr/local/nginx/conf/nginx.conf配置如下:

user  nobody;
worker_processes  auto;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    use epoll;
    worker_connections  1024;
}


stream {
    server {
        listen 3000 udp;
        proxy_pass 127.0.0.1:3001;

    }
}

这里写一个my_socket_server.py侦听在3001端口,用于接收UDP数据:

# coding=utf-8

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

sock.bind(('127.0.0.1', 3001))

print ('start server on [%s]:%s' % ('127.0.0.1', 3001))

while True:
    data, addr = sock.recvfrom(1024)
    print ('Received from %s:%s' % (addr,data))
    sock.sendto(b'Hello, %s!' % data, addr)

再写一个my_socket_client.py用于向Nginx侦听的3000端口发送数据:

# coding=utf-8

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:
    data = raw_input('Input msg: ')
    if len(data) == 0:
        continue
    s.sendto(data.encode(), ('127.0.0.1', 3000))
    print (s.recv(1024).decode('utf-8'))

同时运行两个脚本,在client端发送数据:

UDP转发遇到的一个坑

修改下client脚本,改为连续发送2000个数据包:

# coding=utf-8

import socket


s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

for data in range(2000):
    s.sendto(str(data).encode(), ('127.0.0.1', 3000))
    print (s.recv(1024).decode('utf-8'))

然后运行client脚本,发现经常会遇到如下情况:

由图可知只成功了511个。

查看文档得知listen指令有个backlog参数,此参数在Linux系统中默认为511:

悲剧的是backlog参数和udp参数不能同时使用。

Linux 实践

Linux系统编写Systemd Service实践

Linux系统编写Systemd Service实践

Systemd 服务是一种以 .service 结尾的单元(unit)配置文件,用于控制由Systemd 控制或监视的进程。简单说,用于后台以守护精灵(daemon)的形式运行程序。Systemd 广泛应用于新版本的RHEL、SUSE Linux Enterprise、CentOS、Fedora和openSUSE中,用于替代旧有的服务管理器service。

开始

Systemd 服务的内容主要分为三个部分,控制单元(unit)的定义、服务(service)的定义、以及安装部分。服务的路径位于/etc/systemd/system目录(系统的服务位于/usr/lib/systemd/system),以 .service 结尾的单元(unit)配置文件,这篇文章以创建nginx service为例,这里假设您已经自行编译安装好了nginx,下面我们来创建一个nginx service

#创建一个nginx.service文件
vi /etc/systemd/system/nginx.service

内容如下:

[Unit]
Description=Nginx - high performance web server
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop

[Install]
WantedBy=multi-user.target

输入命令systemctl daemon-reload来加载刚刚创建的nginx服务,这样我们就可以用Systemd的方式来管理nginx了,命令如下:

#启动nginx
systemctl start nginx
#重载nginx
systemctl reload nginx
#停止nginx
systemctl stop nginx
#重启nginx
systemctl restart nginx
#如果需要开机启动
systemctl enable nginx
#如果需要取消开机启动
systemctl disable nginx

定义控制单元 [Unit]

从上面的例子中我们看到Unit内容如下:

[Unit]
Description=Nginx - high performance web server
After=network.target

定义服务本体 [service]

上面的Service中服务本体内容为:

[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop

其实服务本体中还有更多的参数,这里在额外列举一些常用的参数:

安装服务 [install]

上面例子中安装服务内容为:

[Install]
WantedBy=multi-user.target

总结

Systemd Service 是一种替代/etc/init.d/下脚本的更好方式,它可以灵活的控制你什么时候要启动服务,一般情况下也不会造成系统无法启动进入紧急模式。所以如果想设置一些开机启动的东西,可以试着写 Systemd Service。当然了,前提是你使用的Linux发行版是支持它的才行。

Linux 实践

Linux安装rinetd实现TCP/UDP端口转发

Linux安装rinetd实现TCP/UDP端口转发

在Linux系统中大多数情况选择用iptables来实现端口转发,iptables虽然强大,但配置不便,而且新手容易出错。在此分享另一个TCP/UDP端口转发工具rinetd,rinetd体积小巧,配置也很简单。

安装rinetd

这篇文章以CentOS 7为例,复制下面的命令输入,一行一个:

#安装依赖
yum -y install gcc gcc-c++ make
#下载rinetd
wget https://github.com/samhocevar/rinetd/releases/download/v0.70/rinetd-0.70.tar.gz
#解压
tar -zxvf rinetd-0.70.tar.gz
#进入目录
cd rinetd-0.70
#编译安装
./bootstrap
./configure
make && make install

安装后,可以输入rinetd -v查看当前版本。

[root@kryptcn2 rinetd-0.70]# rinetd -v
rinetd 0.70

随着时间推移,上面下载地址不一定是最新的,大家可前往Github:https://github.com/samhocevar/rinetd/releases下载最新版本。

设置TCP端口转发

#新建rinetd配置文件
vi /etc/rinetd.conf
#填写如下内容
0.0.0.0 2018 103.74.192.160 2019
#启动rinetd
rinetd -c /etc/rinetd.conf

rinetd配置文件的格式如下:

上面配置的意思是将本地2018端口转发到103.74.192.160的2019端口,启动后可以输入netstat -apn|grep 'rinetd'查看是否运行正常,注意还需要在自己服务器防火墙放行对应的源端口,否则无法正常使用用。

0.70版本开始rinetd已经支持UDP转发,写法如下:

127.0.0.1   8000/udp  192.168.1.2     8000/udp

创建systemd服务

为了方便管理,我们可以为rinetd编写一个systemd服务,有兴趣的同学可参考《Linux系统编写Systemd Service实践》,xiaoz已经编写好了,直接复制下面的内容即可:

#创建rinetd服务
vi /etc/systemd/system/rinetd.service

复制下面的内容进行保存:

[Unit]
Description=rinetd
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/sbin/rinetd -c /etc/rinetd.conf

[Install]
WantedBy=multi-user.target

输入命令:systemctl daemon-reload重载daemon使其生效,然后就可以使用下面的命令来管理rinetd了。

#启动rinetd
systemctl start rinetd
#设置开机启动
systemctl enable rinetd
#停止rinetd
systemctl stop rinetd
#重启
systemctl restart rinetd

rinetd的一些问题

rinetd支持转发到域名,rinetd会提前解析域名,并将解析出的IP缓存到内存中,如果您的域名解析IP发生了变化必须重启rinetd才会生效,所以rinetd并不适合转发到域名IP经常发生变化的情况,而socat则不存在此问题。

其它转发工具

总结

rinetd安装和配置都非常简单,并且从0.70版本开始已经支持UDP转发,但rinetd具体性能如何xiaoz并未进一步测试,不知道高并发的情况下能否扛得住。

项目地址:https://github.com/samhocevar/rinetd

Linux 实践

使用Nginx进行TCP/UDP端口转发

使用Nginx进行TCP/UDP端口转发

Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。在1.9.13版本后,Nginx已经支持端口转发。之前分享过《Linux安装rinetd实现TCP端口转发》,rinetd配置简单,使用方便,但遗憾的是不支持UDP转发。如果需要同时支持TCP/UDP端口转发可以使用Nginx

安装Nginx

可以自行去官方http://nginx.org/下载最新版本Nginx编译安装,注意版本一定要大于1.9.1,编译的时候需要--with-stream这个模块支持。

编译方法这里就不介绍了,这篇文章直接使用xiaoz写好的一键脚本安装Nginx,省时、省力,直接执行下面的命令即可。

#执行下面的命令,根据提示完成安装
wget https://raw.githubusercontent.com/helloxz/nginx-cdn/master/nginx.sh && bash nginx.sh
#安装完成后执行下面的命令让环境变量生效
source /etc/profile
#执行下面的命令查看nginx信息
nginx -V

端口转发

nginx.conf添加如下配置,并使用nginx -s reload重载nginx使其生效,同时注意防火墙/安全组放行对应的端口。

stream {
    #将12345端口转发到192.168.1.23的3306端口
    server {
        listen 12345;
        proxy_connect_timeout 5s;
        proxy_timeout 20s;
        proxy_pass 192.168.1.23:3306;
    }
    #将udp 53端口转发到192.168.1.23 53端口
    server {
        listen 53 udp reuseport;
        proxy_timeout 20s;
        proxy_pass 192.168.1.23:53;
    }
    #ipv4转发到ipv6
    server {
        listen 9135;
        proxy_connect_timeout 10s;
        proxy_timeout 30s;
        proxy_pass [2607:fcd0:107:3cc::1]:9135;
    }
}

注意:nginx可以将IPV4的数据包转发到IPV6,IPV6的IP需要使用[]括起来。

总结

目前能实现端口转发的工具大致有:rinetd、SSH、iptables、nginx、haproxy,其中rinetd配置最为简单,但不支持UDP转发,并且该软件已经好几年未更新,如果您服务器上已经安装了nginx,不妨用nginx做端口转发。

此文部分内容参考了:

其它nginx相关文章

Linux 实践

linux系统中rsync+inotify实现服务器之间文件实时同步

linux系统中rsync+inotify实现服务器之间文件实时同步

与传统的cp、tar备份方式相比,rsync具有安全性高、备份迅速、支持增量备份等优点,通过rsync可以解决对实时性要求不高的数据备份需求,例如定期的备份文件服务器数据到远端服务器,对本地磁盘定期做数据镜像等。 随着应用系统规模的不断扩大,对数据的安全性和可靠性也提出的更好的要求,rsync在高端业务系统中也逐渐暴露出了很多不足,首先,rsync同步数据时,需要扫描所有文件后进行比对,进行差量传输。如果文件数量达到了百万甚至千万量级,扫描所有文件将是非常耗时的。而且正在发生变化的往往是其中很少的一部分,这是非常低效的方式。其次,rsync不能实时的去监测、同步数据,虽然它可以通过linux守护进程的方式进行触发同步,但是两次触发动作一定会有时间差,这样就导致了服务端和客户端数据可能出现不一致,无法在应用故障时完全的恢复数据。基于以上原因,rsync+inotify组合出现了!

 1. rsync ---- remote synchronize  ,是一款实现远程同步功能的软件;

 2. rsync使用“Rsync算法”来同步文件,该算法只传送两个文件的不同部分,因此速度相当快;

 3. 同步文件的同时,可以保持原来文件的权限、时间 和目录结构;

 4. 对于多个文件来说,内部流水线减少文件等待的延时;

 5. rsync默认监听TCP 873端口,通过远程shell如rsh和ssh复制文件。同时要求必须在远程和本地系统上都安装sync.

Inotify 是一种强大的、细粒度的、异步的文件系统事件监控机制,linux内核从2.6.13起,加入了Inotify支持,通过Inotify可以监控文件系统中添加、删除,修改、移动等各种细微事件,利用这个内核接口,第三方软件就可以监控文件系统下文件的各种变化情况,而 inotify-tools 就是这样的一个第三方软件。 在上面章节中,我们讲到,rsync可以实现触发式的文件同步,但是通过 crontab 守护进程方式进行触发,同步的数据和实际数据会有差异,而inotify可以监控文件系统的各种变化,当文件有任何变动时,就触发rsync同步,这样刚好解决了同步数据的实时性问题。 具体大家可以参照http://www.ibm.com/developerworks/cn/linux/l-ubuntu-inotify/index.html来进行学习。


接下面我们来开始进行rsync与inotify的安装、配置、测试。

下面是2个服务器的结构,分别为主机名、ip、同步的目录,并将2台服务器均是CentOS 6.5发行版本。

Host IP Docoment
Server 192.168.1.21 /tmp
Client 192.168.1.22 /tmp

主服务器(Server)

其中主服务器需要安装rsync与inotify,主服务器作为server,向备份服务器client传输文件

1、安装rsync

该版本的已安装rsync,如果没有,可使用yum安装(也可以使用源码安装,这里就不多做介绍了):

#安装rsync和xinetd,并创建目录:
yum install rsync xinetd

#配置xinetd:
vi /etc/xinetd.d/rsync
#disable = yes修改为
disable = no

启动xinetd服务:
service xinetd start

2、建立密码认证文件

代码如下:

[root@Server ]# echo "rsync-pwd" >/etc/rsync.passwd 
#其中rsync-pwd可以自己设置密码,rsync.passwd名字也可以自己设置

[root@Server]# chmod 600 /etc/rsync.passwd 
#无论是为了安全,还是为了避免出现以下错误,密码文件都需要给600权限
  1. 配置文件

rsync的主要有以下三个配置文件:

  rsyncd.conf      ----主配置文件,需要手动生成

  rsyncd.secrets  ----密码文件

  rsyncd.motd     ----rysnc服务器信息

3、安装inotify

[root@Server]# cd /usr/src/ 
[root@Server src]# wget http://cloud.github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz 
[root@Server src]# tar zxvf inotify-tools-3.14.tar.gz 
[root@Server src]# cd inotify-tools-3.14 
[root@Server inotify-tools-3.14]# ./configure --prefix=/usr/local/inotify 
[root@Server inotify-tools-3.14]# make 
[root@Server inotify-tools-3.14]# make install

4、创建rsync复制脚本

此项功能主要是将server端的目录/tmp里的内容,如果修改了(无论是添加、修改、删除文件)能够通过inotify监控到,并通过rsync实时的同步给client的/tmp里,下面是通过shell脚本实现的。

#!/bin/bash 
host=192.168.1.22
src=/tmp/     
des=web 
user=webuser 
/usr/local/inotify/bin/inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w%f%e' -e modify,delete,create,attrib $src \ 
| while read files 
do 
/usr/bin/rsync -vzrtopg --delete --progress --password-file=/usr/local/rsync/rsync.passwd $src $user@$host::$des 
echo "${files} was rsynced" >>/tmp/rsync.log 2>&1 
done

注意:建议各位吧rsync的日志放到其他的目录下(非备份目录)。 其中host是client的ip,src是server端要实时监控的目录,des是认证的模块名,需要与client一致,user是建立密码文件里的认证用户。 把这个脚本命名为rsync.sh,放到监控的目录里,比如我的就放到/tmp下面,并给予764权限

[root@Server tmp]# chmod 764 rsync.sh

然后运行这个脚本

[root@Server tmp]# sh /tmp/rsync.sh &

请记住,只有在备份服务器client端的rsync安装并启动rsync之后,在启动rsync.sh脚本,否则有时候会满屏出现:

rsync: failed to connect to 192.168.1.22: Connection refused (111)
rsync error: error in socket IO (code 10) at clientserver.c(107) [sender=2.6.8]

我们还可以把rsync.sh脚本加入到开机启动项里

[root@Server tmp]# echo "/tmp/rsync.sh" >> /etc/rc.local 

备份服务器(Client)

1、安装rsync(备份服务器只安装rsync)

#安装rsync和xinetd,并创建目录:
yum install rsync xinetd

#配置xinetd:
vi /etc/xinetd.d/rsync
#disable = yes修改为
disable = no

启动xinetd服务:
service xinetd start

2、建立用户与密码认证文件

[root@Client]# echo "webuser:rsync-pwd" > /etc/rsync.passwd
#请记住,在server端建立的密码文件,只有密码,没有用户名;而在备份服务端client里建立的密码文件,用户名与密码都有。

[root@Client]# chmod 600 /etc/rsync.passwd 
#需要给密码文件600权限

3、建立rsync配置文件

vim /etc/rsyncd.conf

uid = root 
gid = root 
use chroot = no 
max connections = 10 
strict modes = yes 
pid file = /var/run/rsyncd.pid 
lock file = /var/run/rsync.lock 
log file = /var/log/rsyncd.log 
[web] 
path = /tmp/ 
comment = web file 
ignore errors 
read only = no 
write only = no 
hosts allow = 192.168.10.220 
hosts deny = * 
list = false 
uid = root 
gid = root 
auth users = webuser 
secrets file = /usr/local/rsync/rsync.passwd

其中web是server服务端里的认证模块名称,需要与主服务器里的一致,以上的配置我的自己服务器里的配置,以供参考。

4、启动rsync

service xinetd start
chkconfig xinetd on   #设置开机自启动

测试

现在rsync与inotify在server端安装完成,rsync在备份服务器client端也安装完成。接下来就可以来测试一下:

在server里创建个test-rsync文件,看看client是否能收到

[root@Server tmp]# touch test-rsync

再看client端是否有test-rsync文件,同时client端的tmp目录文件是否与server端的文件完全一致。如果一致,则表示已经设置成功。

配置文件详细说明:

注释:

 uid = nobody

进行同步或者备份的用户,nobody 为任何用户

gid = nobody 

进行备份的组,nobody为任意组

use chroot = no

如果"use chroot"指定为true,那么rsync在传输文件以前首先chroot到path参数所指定的目录下。这样做的原因是实现额外的安全防护,但是缺点是需要以root权限,并且不能备份指向外部的符号连接所指向的目录文件。默认情况下chroot值为true.但是一般不需要,选择no或false

list = no

不允许列清单

max connections = 10 

最大连接数

timeout = 600 

覆盖客户指定的IP超时时间,也就是说rsync服务器不会永远等待一个崩溃的客户端。

pidfile = /var/run/rsyncd.pid  

pid文件的存放位置

lock file = /var/run/rsync.lock  

锁文件的存放位置

log file = /var/log/rsyncd.log   

日志文件的存放位置

[data]  

这里是认证模块名,即跟samba语法一样,是对外公布的名字

path = /home/backup

这里是参与同步的目录

ignore errors  

可以忽略一些无关的IO错误

read only = no

允许可读可写

list = no

不允许列清单

hosts allow = 192.168.1.0/255.255.255.0

这里可以指定单个IP,也可以指定整个网段,能提高安全性。格式是ip 与ip 之间、ip和网段之间、网段和网段之间要用空格隔开

auth users = test 

认证的用户名

secrets file = /etc/rsyncd.password  

密码文件存放地址

注意:

1、[backup] 认证模块名和 path = /www/backup/ 参与同步的目录

这里的path 大家要记好了,这里不要随便的一设置就直接完事,要知道这里是认证模块的,以后从客户机备份的数据会存储在这里。

2、auth users = redhat 认证的用户名 这个名字是服务器端实实在在存在用户,大家不要直接跟步骤走却忽略了这点。如果服务器端少了这个的话我估计你的数据同步就实现不了,大家要谨记。

Linux 实践

rsync 用法教程

rsync 用法教程

简介

rsync 是一个常用的 Linux 应用程序,用于文件同步。

它可以在本地计算机与远程计算机之间,或者两个本地目录之间同步文件(但不支持两台远程计算机之间的同步)。它也可以当作文件复制工具,替代 cpmv 命令。

它名称里面的 r 指的是 remote,rsync 其实就是"远程同步"(remote sync)的意思。与其他文件传输工具(如 FTP 或 scp)不同,rsync 的最大特点是会检查发送方和接收方已有的文件,仅传输有变动的部分(默认规则是文件大小或修改时间有变动)。

安装

如果本机或者远程计算机没有安装 rsync,可以用下面的命令安装。

# Debian
$ sudo apt-get install rsync

# Red Hat
$ sudo yum install rsync

# Arch Linux
$ sudo pacman -S rsync

注意,传输的双方都必须安装 rsync。

基本用法

-r 参数

本机使用 rsync 命令时,可以作为 cpmv 命令的替代方法,将源目录同步到目标目录。

$ rsync -r source destination

上面命令中, -r 表示递归,即包含子目录。注意, -r 是必须的,否则 rsync 运行不会成功。 source 目录表示源目录, destination 表示目标目录。

如果有多个文件或目录需要同步,可以写成下面这样。

$ rsync -r source1 source2 destination

上面命令中, source1source2 都会被同步到 destination 目录。

-a 参数

-a 参数可以替代 -r ,除了可以递归同步以外,还可以同步元信息(比如修改时间、权限等)。由于 rsync 默认使用文件大小和修改时间决定文件是否需要更新,所以 -a-r 更有用。下面的用法才是常见的写法。

$ rsync -a source destination

目标目录 destination 如果不存在,rsync 会自动创建。执行上面的命令后,源目录 source 被完整地复制到了目标目录 destination 下面,即形成了 destination/source 的目录结构。

如果只想同步源目录 source 里面的内容到目标目录 destination ,则需要在源目录后面加上斜杠。

$ rsync -a source/ destination

上面命令执行后, source 目录里面的内容,就都被复制到了 destination 目录里面,并不会在 destination 下面创建一个 source 子目录。

-n 参数

如果不确定 rsync 执行后会产生什么结果,可以先用 -n--dry-run 参数模拟执行的结果。

$ rsync -anv source/ destination

上面命令中, -n 参数模拟命令执行的结果,并不真的执行命令。 -v 参数则是将结果输出到终端,这样就可以看到哪些内容会被同步。

--delete 参数

默认情况下,rsync 只确保源目录的所有内容(明确排除的文件除外)都复制到目标目录。它不会使两个目录保持相同,并且不会删除文件。如果要使得目标目录成为源目录的镜像副本,则必须使用 --delete 参数,这将删除只存在于目标目录、不存在于源目录的文件。

$ rsync -av --delete source/ destination

上面命令中, --delete 参数会使得 destination 成为 source 的一个镜像。

排除文件

--exclude 参数

有时,我们希望同步时排除某些文件或目录,这时可以用 --exclude 参数指定排除模式。

$ rsync -av --exclude='*.txt' source/ destination
# 或者
$ rsync -av --exclude '*.txt' source/ destination

上面命令排除了所有 TXT 文件。

注意,rsync 会同步以"点"开头的隐藏文件,如果要排除隐藏文件,可以这样写 --exclude=".*"

如果要排除某个目录里面的所有文件,但不希望排除目录本身,可以写成下面这样。

$ rsync -av --exclude 'dir1/*' source/ destination

多个排除模式,可以用多个 --exclude 参数。

$ rsync -av --exclude 'file1.txt' --exclude 'dir1/*' source/ destination

多个排除模式也可以利用 Bash 的大扩号的扩展功能,只用一个 --exclude 参数。

$ rsync -av --exclude={'file1.txt','dir1/*'} source/ destination

如果排除模式很多,可以将它们写入一个文件,每个模式一行,然后用 --exclude-from 参数指定这个文件。

$ rsync -av --exclude-from='exclude-file.txt' source/ destination

--include 参数

--include 参数用来指定必须同步的文件模式,往往与 --exclude 结合使用。

$ rsync -av --include="*.txt" --exclude='*' source/ destination

上面命令指定同步时,排除所有文件,但是会包括 TXT 文件。

远程同步

SSH 协议

rsync 除了支持本地两个目录之间的同步,也支持远程同步。它可以将本地内容,同步到远程服务器。

$ rsync -av source/ username@remote_host:destination

也可以将远程内容同步到本地。

$ rsync -av username@remote_host:source/ destination

rsync 默认使用 SSH 进行远程登录和数据传输。

由于早期 rsync 不使用 SSH 协议,需要用 -e 参数指定协议,后来才改的。所以,下面 -e ssh 可以省略。

$ rsync -av -e ssh source/ user@remote_host:/destination

但是,如果 ssh 命令有附加的参数,则必须使用 -e 参数指定所要执行的 SSH 命令。

$ rsync -av -e 'ssh -p 2234' source/ user@remote_host:/destination

上面命令中,-e参数指定 SSH 使用2234端口。

rsync 协议

除了使用 SSH,如果另一台服务器安装并运行了 rsync 守护程序,则也可以用 rsync:// 协议(默认端口873)进行传输。具体写法是服务器与目标目录之间使用双冒号分隔 ::

$ rsync -av source/ 192.168.122.32::module/destination

注意,上面地址中的 module 并不是实际路径名,而是 rsync 守护程序指定的一个资源名,由管理员分配。

如果想知道 rsync 守护程序分配的所有 module 列表,可以执行下面命令。

$ rsync rsync://192.168.122.32

rsync 协议除了使用双冒号,也可以直接用 rsync:// 协议指定地址。

$ rsync -av source/ rsync://192.168.122.32/module/destination

增量备份

rsync 的最大特点就是它可以完成增量备份,也就是默认只复制有变动的文件。

除了源目录与目标目录直接比较,rsync 还支持使用基准目录,即将源目录与基准目录之间变动的部分,同步到目标目录。

具体做法是,第一次同步是全量备份,所有文件在基准目录里面同步一份。以后每一次同步都是增量备份,只同步源目录与基准目录之间有变动的部分,将这部分保存在一个新的目标目录。这个新的目标目录之中,也是包含所有文件,但实际上,只有那些变动过的文件是存在于该目录,其他没有变动的文件都是指向基准目录文件的硬链接。

$ rsync -a --delete --link-dest /compare/path /source/path /target/path

下面是一个脚本示例,备份用户的主目录。

#!/bin/bash

# A script to perform incremental backups using rsync

set -o errexit
set -o nounset
set -o pipefail

readonly SOURCE_DIR="${HOME}"
readonly BACKUP_DIR="/mnt/data/backups"
readonly DATETIME="$(date '+%Y-%m-%d_%H:%M:%S')"
readonly BACKUP_PATH="${BACKUP_DIR}/${DATETIME}"
readonly LATEST_LINK="${BACKUP_DIR}/latest"

mkdir -p "${BACKUP_DIR}"

rsync -av --delete \
  "${SOURCE_DIR}/" \
  --link-dest "${LATEST_LINK}" \
  --exclude=".cache" \
  "${BACKUP_PATH}"

rm -rf "${LATEST_LINK}"
ln -s "${BACKUP_PATH}" "${LATEST_LINK}"

上面脚本中,每一次同步都会生成一个新目录 ${BACKUP_DIR}/${DATETIME} ,并将软链接 ${BACKUP_DIR}/latest 指向这个目录。下一次备份时,就将 ${BACKUP_DIR}/latest 作为基准目录,生成新的备份目录。最后,再将软链接 ${BACKUP_DIR}/latest 指向新的备份目录。

配置项

-a--archive 参数表示存档模式,保存所有的元数据,比如修改时间(modification time)、权限、所有者等,并且软链接也会同步过去。

--append 参数指定文件接着上次中断的地方,继续传输。

--append-verify 参数跟 --append 参数类似,但会对传输完成后的文件进行一次校验。如果校验失败,将重新发送整个文件。

-b--backup 参数指定在删除或更新目标目录已经存在的文件时,将该文件更名后进行备份,默认行为是删除。更名规则是添加由 --suffix 参数指定的文件后缀名,默认是~。

--backup-dir 参数指定文件备份时存放的目录,比如 --backup-dir=/path/to/backups

--bwlimit 参数指定带宽限制,默认单位是 KB/s ,比如 --bwlimit=100

-c--checksum 参数改变 rsync 的校验方式。默认情况下,rsync 只检查文件的大小和最后修改日期是否发生变化,如果发生变化,就重新传输;使用这个参数以后,则通过判断文件内容的校验和,决定是否重新传输。

--delete 参数删除只存在于目标目录、不存在于源目标的文件,即保证目标目录是源目标的镜像。

-e 参数指定使用 SSH 协议传输数据。

--exclude 参数指定排除不进行同步的文件,比如 --exclude="*.iso"

--exclude-from 参数指定一个本地文件,里面是需要排除的文件模式,每个模式一行。

--existing--ignore-non-existing 参数表示不同步目标目录中不存在的文件和目录。

-h 参数表示以人类可读的格式输出。

-h--help 参数返回帮助信息。

-i 参数表示输出源目录与目标目录之间文件差异的详细情况。

--ignore-existing 参数表示只要该文件在目标目录中已经存在,就跳过去,不再同步这些文件。

--include 参数指定同步时要包括的文件,一般与 --exclude 结合使用。

-m 参数指定不同步空目录。

--max-size 参数设置传输的最大文件的大小限制,比如不超过 200KB(--max-size='200k')

--min-size 参数设置传输的最小文件的大小限制,比如不小于 10KB(--min-size=10k)

-n 参数或 --dry-run 参数模拟将要执行的操作,而并不真的执行。配合 -v 参数使用,可以看到哪些内容会被同步过去。

-P 参数是 --progress--partial 这两个参数的结合。

--partial 参数允许恢复中断的传输。不使用该参数时, rsync 会删除传输到一半被打断的文件;使用该参数后,传输到一半的文件也会同步到目标目录,下次同步时再恢复中断的传输。一般需要与 --append--append-verify 配合使用。

--partial-dir 参数指定将传输到一半的文件保存到一个临时目录,比如 --partial-dir=.rsync-partial 。一般需要与 --append--append-verify 配合使用。

--progress 参数表示显示进展。

-r 参数表示递归,即包含子目录。

--remove-source-files 参数表示传输成功后,删除发送方的文件。

--size-only 参数表示只同步大小有变化的文件,不考虑文件修改时间的差异。

--suffix 参数指定文件名备份时,对文件名添加的后缀,默认是 ~

-u--update 参数表示同步时跳过目标目录中修改时间更新的文件,即不同步这些有更新的时间戳的文件。

-v 参数表示输出细节。 -vv 表示输出更详细的信息, -vvv 表示输出最详细的信息。

--version 参数返回 rsync 的版本。

-z参数指定同步时压缩数据。

参考链接

How To Use Rsync to Sync Local and Remote Directories on a VPS, Justin Ellingwood

Mirror Your Web Site With rsync, Falko Timme

Examples on how to use Rsync, Egidio Docile

How to create incremental backups using rsync on Linux, Egidio Docile

(完)

Linux 实践

Centos 6无法使用yum解决办法(centos6停止更新)

Centos 6无法使用yum解决办法(centos6停止更新)

12月后Centos 6 系统无法使用yum出现错误

相信已经有一部分朋友今天连接到CentOS 6的服务器后执行yum后发现报错,那么发生了什么?

CentOS 6已经随着2020年11月的结束进入了EOL(Reaches End of Life),不过有一些老设备依然需要支持,CentOS官方也给这些还不想把CentOS 6扔进垃圾堆的用户保留了最后一个版本的镜像,只是这个镜像不会再有更新了

官方便在12月2日正式将CentOS 6相关的软件源移出了官方源,随之而来逐级镜像也会陆续将其删除。

不过有一些老设备依然需要维持在当前系统,CentOS官方也给这些还不想把CentOS 6扔进垃圾堆的用户保留了各个版本软件源的镜像,只是这个软件源不会再有更新了。

一键修复

sed -i "s|enabled=1|enabled=0|g" /etc/yum/pluginconf.d/fastestmirror.conf
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
curl -o /etc/yum.repos.d/CentOS-Base.repo https://www.xmpan.com/Centos-6-Vault-Aliyun.repo
yum clean all
yum makecache

手动修复教程:

首先把fastestmirrors关了

#编辑
vi /etc/yum/pluginconf.d/fastestmirror.conf
#修改
enable=0
#或者执行以下命令
sed -i "s|enabled=1|enabled=0|g" /etc/yum/pluginconf.d/fastestmirror.conf

先把之前的repo挪到备份,然后下面两个二选一

  1. 备份
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
  1. 替换为官方Vault源(海外服务器用)
curl -o /etc/yum.repos.d/CentOS-Base.repo https://www.xmpan.com/Centos-6-Vault-Official.repo

或者替换为阿里云Vault镜像(国内服务器用)

curl -o /etc/yum.repos.d/CentOS-Base.repo https://www.xmpan.com/Centos-6-Vault-Aliyun.repo
Linux 实践

Nginx配置中不同请求匹配不同请求

Nginx配置中不同请求匹配不同请求

一、正则匹配

  1. ~ 为区分大小写匹配
  2. ~* 为不区分大小写匹配
  3. !和!*分别为区分大小写不匹配及不区分大小写不匹配

二、文件及目录匹配

  1. -f和!-f用来判断是否存在文件
  2. -d和!-d用来判断是否存在目录
  3. -e和!-e用来判断是否存在文件或目录
  4. -x和!-x用来判断文件是否可执行

三.rewrite指令的最后一项参数为flag标记,flag标记有:

  1. last 相当于apache里面的[L]标记,表示rewrite。
  2. break本条规则匹配完成后,终止匹配,不再匹配后面的规则。
  3. redirect 返回302临时重定向,浏览器地址会显示跳转后的URL地址。
  4. permanent 返回301永久重定向,浏览器地址会显示跳转后的URL地址。

使用last和break实现URI重写,浏览器地址栏不变。而且两者有细微差别,使用alias指令必须用last标记;使用proxy_pass指令时,需要使用break标记。Last标记在本条rewrite规则执行完毕后,会对其所在server{…}标签重新发起请求,而break标记则在本条规则匹配完成后,终止匹配。

四.NginxRewrite 规则相关指令

1.break指令

使用环境:server,location,if;

该指令的作用是完成当前的规则集,不再处理rewrite指令。

2.if指令

使用环境:server,location

该指令用于检查一个条件是否符合,如果条件符合,则执行大括号内的语句。If指令不支持嵌套,不支持多个条件&&和||处理。

location /CMS/ {##请求以CMS开头的走此location
    if ($request_uri ~ "CMS/was") { ##内容包含 CMS/was 的转发至以下请求(区分大小写)
        proxy_pass http://10.1.1.247;
        break;  ##break表示
    }
    if ($request_uri ~ "CMS/Evaluate.action") { ##同上
        proxy_pass http://10.1.1.247;
        break;
    }
     rewrite ^ http://www.baidu.com/;##CMS后其余的请求统一重定向至百度
}

3.return指令

语法:returncode ;

使用环境:server,location,if;

该指令用于结束规则的执行并返回状态码给客户端。

location ~ .*\.(sh|bash)?$ {
   return 403;
}

4.rewrite 指令

语法:rewriteregex replacement flag

使用环境:server,location,if

该指令根据表达式来重定向URI,或者修改字符串。指令根据配置文件中的顺序来执行。注意重写表达式只对相对路径有效。如果你想配对主机名,你应该使用if语句,示例如下:

if( $host ~* www\.(.*) ) {
   set $host_without_www $1;
   rewrite ^(.*)$  http://$host_without_www$1permanent;
}

5.Set指令

语法:setvariable value ; 默认值:none; 使用环境:server,location,if;

该指令用于定义一个变量,并给变量赋值。变量的值可以为文本、变量以及文本变量的联合。

set$varname "hello world";

6.Uninitialized_variable_warn指令

语法:uninitialized_variable_warnon|off

使用环境:http,server,location,if

该指令用于开启和关闭未初始化变量的警告信息,默认值为开启。 

五.Nginx的Rewrite规则编写实例

1.当访问的文件和目录不存在时,重定向到某个html文件

if( !-e $request_filename )
{
    rewrite ^/(.*)$ index.htmllast;
}

2.目录对换 /123456/xxxx ====> /xxxx?id=123456 

rewrite ^/(\d+)/(.+)/  /$2?id=$1 last;

3.如果客户端使用的是IE浏览器,则重定向到/ie目录下

if( $http_user_agent  ~ MSIE)
{
    rewrite ^(.*)$ /ie/$1 break;
}

4.禁止访问多个目录

location ~ ^/(cron|templates)/
{
    deny all;
    break;
}

5.禁止访问以/data开头的文件

location ~ ^/data
{
    deny all;
}

6.禁止访问以.sh,.flv,.mp3为文件后缀名的文件

location ~ .*\.(sh|flv|mp3)$
{
    return 403;
}

7.设置某些类型文件的浏览器缓存时间 

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
    expires 30d;
}
location ~ .*\.(js|css)$
{
    expires 1h;
}

8.给favicon.ico和robots.txt设置过期时间;

这里为favicon.ico为99天,robots.txt为7天并不记录404错误日志

location ~(favicon.ico) {
   log_not_found off;
   expires 99d;
   break;
}
location ~(robots.txt) {
   log_not_found off;
   expires 7d;
   break;
}

9.设定某个文件的过期时间;这里为600秒,并不记录访问日志

location ^~ /html/scripts/loadhead_1.js {
    access_log  off;
    root /opt/lampp/htdocs/web;
    expires 600;
    break;
}

10.文件反盗链并设置过期时间

这里的return412 为自定义的http状态码,默认为403,方便找出正确的盗链的请求

rewrite ^/ http: //img.linuxidc.net/leech.gif;//显示一张防盗链图片
access_log off; //不记录访问日志,减轻压力
expires 3d //所有文件3天的浏览器缓存
 
location ~*^.+\.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ {
  valid_referers none blocked *.linuxidc.com*.linuxidc.net localhost 208.97.167.194;
if ($invalid_referer) {
     rewrite ^/ http://img.linuxidc.net/leech.gif;
     return 412;
     break;
}
access_log  off;
root /opt/lampp/htdocs/web;
expires 3d;
break;
}

11.只允许固定ip访问网站,并加上密码

root /opt/htdocs/www;
allow  208.97.167.194;
allow  222.33.1.2;
allow  231.152.49.4;
deny  all;
auth_basic “C1G_ADMIN”;
auth_basic_user_file htpasswd;

12.将多级目录下的文件转成一个文件,增强seo效果 

/job-123-456-789.html 指向/job/123/456/789.html
 
rewrite^/job-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /job/$1/$2/jobshow_$3.html last;

14.将根目录下某个文件夹指向2级目录

如/shanghaijob/ 指向 /area/shanghai/
如果你将last改成permanent,那么浏览器地址栏显是/location/shanghai/
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2last;
上面例子有个问题是访问/shanghai时将不会匹配
rewrite ^/([0-9a-z]+)job$ /area/$1/ last;
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2last;
这样/shanghai 也可以访问了,但页面中的相对链接无法使用,
如./list_1.html真实地址是/area/shanghia/list_1.html会变成/list_1.html,导至无法访问。
那我加上自动跳转也是不行咯
(-d $request_filename)它有个条件是必需为真实目录,而我的rewrite不是的,所以没有效果
if (-d $request_filename){
rewrite ^/(.*)([^/])$ http://$host/$1$2/permanent;
}
知道原因后就好办了,让我手动跳转吧
rewrite ^/([0-9a-z]+)job$ /$1job/permanent;
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2last;

15.域名跳转

server{
  listen      80;
  server_name  jump.linuxidc.com;
  index index.html index.htm index.php;
  root  /opt/lampp/htdocs/www;
  rewrite ^/ http://www.linuxidc.com/;
  access_log  off;
}

16.多域名转向

server_name  www.linuxidc.com www.linuxidc.net;
index index.html index.htm index.php;
root  /opt/lampp/htdocs;
if ($host ~ "linuxidc\.net") {
    rewrite ^(.*) http://www.linuxidc.com$1permanent;
}

六.nginx全局变量

arg_PARAMETER    #这个变量包含GET请求中,如果有变量PARAMETER时的值。
args                    #这个变量等于请求行中(GET请求)的参数,如:foo=123&bar=blahblah;
binary_remote_addr #二进制的客户地址。
body_bytes_sent    #响应时送出的body字节数数量。即使连接中断,这个数据也是精确的。
content_length    #请求头中的Content-length字段。
content_type      #请求头中的Content-Type字段。
cookie_COOKIE    #cookie COOKIE变量的值
document_root    #当前请求在root指令中指定的值。
document_uri      #与uri相同。
host                #请求主机头字段,否则为服务器名称。
hostname          #Set to themachine’s hostname as returned by gethostname
http_HEADER
is_args              #如果有args参数,这个变量等于”?”,否则等于”",空值。
http_user_agent    #客户端agent信息
http_cookie          #客户端cookie信息
limit_rate            #这个变量可以限制连接速率。
query_string          #与args相同。
request_body_file  #客户端请求主体信息的临时文件名。
request_method    #客户端请求的动作,通常为GET或POST。
remote_addr          #客户端的IP地址。
remote_port          #客户端的端口。
remote_user          #已经经过Auth Basic Module验证的用户名。
request_completion #如果请求结束,设置为OK. 当请求未结束或如果该请求不是请求链串的最后一个时,为空(Empty)。
request_method    #GET或POST
request_filename  #当前请求的文件路径,由root或alias指令与URI请求生成。
request_uri          #包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。不能修改。
scheme                #HTTP方法(如http,https)。
server_protocol      #请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
server_addr          #服务器地址,在完成一次系统调用后可以确定这个值。
server_name        #服务器名称。
server_port          #请求到达服务器的端口号。

七.Apache和Nginx规则的对应关系

Apache的RewriteCond对应Nginx的if
Apache的RewriteRule对应Nginx的rewrite
Apache的[R]对应Nginx的redirect
Apache的[P]对应Nginx的last
Apache的[R,L]对应Nginx的redirect
Apache的[P,L]对应Nginx的last
Apache的[PT,L]对应Nginx的last

例如:允许指定的域名访问本站,其他的域名一律转向www.linuxidc.net

Apache:
RewriteCond %{HTTP_HOST} !^(.*?)\.aaa\.com$[NC]
RewriteCond %{HTTP_HOST} !^localhost$
RewriteCond %{HTTP_HOST}!^192\.168\.0\.(.*?)$
RewriteRule ^/(.*)$ http://www.linuxidc.net[R,L]

Nginx过滤示例:

if( $host ~* ^(.*)\.aaa\.com$ )
{
   set $allowHost ‘1’;
}
if( $host ~* ^localhost )
{
   set $allowHost ‘1’;
}
if( $host ~* ^192\.168\.1\.(.*?)$ )
{
   set $allowHost ‘1’;
}
if( $allowHost !~ ‘1’ )
{
   rewrite ^/(.*)$ http://www.linuxidc.netredirect ;
}
Linux 实践

使用 flock 文件锁解决 crontab 冲突问题

使用 flock 文件锁解决 crontab 冲突问题

linux 的 crontab 命令,可以定时执行操作,最小周期是每分钟执行一次。但是如果在这一分钟之内,之前的命令并没有执行完成,就会产生冲突。接下来介绍解决冲突的办法,那就是 linux 的 flock 文件锁。

关于crontab实现每秒执行可参考《linux crontab 实现每秒执行》

格式:

flock [-sxun][-w #] fd#

flock [-sxon][-w #] file [-c] command

参数是:

-s, --shared:    获得一个共享锁
-x, --exclusive: 获得一个独占锁
-u, --unlock:    移除一个锁,通常是不需要的,脚本执行完会自动丢弃锁
-n, --nonblock:  如果没有立即获得锁,直接失败而不是等待
-w, --timeout:   如果没有立即获得锁,等待指定时间
-o, --close:     在运行命令前关闭文件的描述符号。用于如果命令产生子进程时会不受锁的管控
-c, --command:   在shell中运行一个单独的命令
-h, --help       显示帮助
-V, --version:   显示版本

继续用回第一个 test.php,文件锁使用独占锁,如果锁定则失败不等待。参数为 -xn 下面是在 crontab 中的使用:

# -xn  文件锁使用独占锁,如果锁定则失败不等待。
* * * * * flock -xn /tmp/test.lock -c 'php /home/develop/test.php >> /home/develop/test.log'

这样当任务未执行完成,下一任务判断到 /tmp/test.lock 被锁定,则结束当前的任务,下一周期再判断。

Linux 实践

Ubuntu扩展 /dev/mapper/ubuntu--vg-ubuntu--lv空间

Ubuntu扩展 /dev/mapper/ubuntu--vg-ubuntu--lv空间

1. 查看磁盘空间

root@root:~# df -h
Filesystem                         Size  Used Avail Use% Mounted on
udev                               1.9G     0  1.9G   0% /dev
tmpfs                              393M  2.1M  391M   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv   14G  4.4G  8.8G  34% /
tmpfs                              2.0G     0  2.0G   0% /dev/shm
tmpfs                              5.0M  4.0K  5.0M   1% /run/lock
tmpfs                              2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/loop0                          90M   90M     0 100% /snap/core/8268
/dev/sda2                          976M   82M  828M   9% /boot
tmpfs                              393M   20K  393M   1% /run/user/125
tmpfs                              393M   56K  393M   1% /run/user/1000

查看vg

root@root:~# vgdisplay
  --- Volume group ---
  VG Name               ubuntu-vg
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  3
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                1
  Open LV               1
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               <79.00 GiB
  PE Size               4.00 MiB
  Total PE              20223
  Alloc PE / Size       3584 / 14.00 GiB
  Free  PE / Size       16639 / <65.00 GiB
  VG UUID               mg1Zau-atla-jy56-ycyN-e6dS-UJC9-1ErQU7

扩展

lvextend -L 120G /dev/mapper/ubuntu--vg-ubuntu--lv     //增大至120G
lvextend -L +20G /dev/mapper/ubuntu--vg-ubuntu--lv     //增加20G
lvreduce -L 50G /dev/mapper/ubuntu--vg-ubuntu--lv      //减小至50G
lvreduce -L -8G /dev/mapper/ubuntu--vg-ubuntu--lv      //减小8G
lvresize -L  30G /dev/mapper/ubuntu--vg-ubuntu--lv     //调整为30G

调整

resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv            //执行调整
Linux 实践

搭建RTMP直播流服务器实现直播

搭建RTMP直播流服务器实现直播

服务介绍

RTMP流媒体服务器,现成的开源方案有很多,有SRS,Red5,wowoza,FMS等,我这里使用的是Nginx的rtmp插件实现实时流转发。

先在 Nginx官网 下载源码包,然后在 github 下载插件包。

为了简化安装过程,网上有很多现成的 nginx + rtmp docker 镜像。下面以 alqutami/rtmp-hls 为例来讲解 rtmp 流媒体服务器的部署。

此 Docker 映像可用于创建开箱即用的支持RTMP、HLS、DASH的视频流服务器。它还允许视频流的自适应流媒体和自定义转码。所有模块都是在 Debian 和 Alpine Linux 基础映像上从源代码构建的。

当前图像是使用以下方法构建的:

部署服务

下载

通过 docker 方式的部署无需安装服务器依赖环境,也不用关心服务器系统发行版。主要需要安装 docker,然后执行以下命令获取镜像:

# pull rtmp-hls image
docker pull alqutami/rtmp-hls

# see rtmp-hls image
docker image ls

# save image
docker image save alqutami/rtmp-hls:latest > alqutami_rtmp-hls_latest.tar.gz

# load image
docker image load < alqutami_rtmp-hls_latest.tar.gz

安装

镜像下载安装之后,即可直接安装运行 rtmp 的 docker container

# base buid
docker run -d --name rtmp -p 1935:1935 -p 8080:8080 alqutami/rtmp-hls:latest

# see container 
docker container exec -it rtmp bash

# delete container 
docker container rm -f rtmp

附件:

调试

流式传输到服务器

查看流

笔记:*

# conf buid
docker run -d \
--name rtmp \
-p 1935:1935 \
-p 8080:8080 \
-v /data/rtmp/nginx.conf:/etc/nginx/nginx.conf \
-v /data/rtmp/html:/usr/local/nginx/html \
alqutami/rtmp-hls:latest
# order conf copy
mkdir -p html/players

docker container cp rtmp:/usr/local/nginx/html/50x.html html/
docker container cp rtmp:/usr/local/nginx/html/index.html html/
docker container cp rtmp:/usr/local/nginx/html/players/dash.html html/players/
docker container cp rtmp:/usr/local/nginx/html/players/hls.html html/players/
docker container cp rtmp:/usr/local/nginx/html/players/hls_hlsjs.html html/players/
docker container cp rtmp:/usr/local/nginx/html/players/rtmp.html html/players/
docker container cp rtmp:/usr/local/nginx/html/players/rtmp_hls.html html/players/
docker container cp rtmp:/usr/local/nginx/html/stat.xsl html/

rtmp 保存修改后的 html 文件的目录 在哪里。

页面调试

# stat page
http://rtmp.wzhz.xyz/stat

# players page
http://rtmp.wzhz.xyz/players/dash.html
http://rtmp.wzhz.xyz/players/hls.html
http://rtmp.wzhz.xyz/players/rtmp.html
http://rtmp.wzhz.xyz/players/rtmp_hls.html
http://rtmp.wzhz.xyz/players/hls_hlsjs.html

Linux 实践

FRP使用

概览

frp 是什么?

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。

为什么使用 frp?

通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括:

安装

关于如何安装 frp 的说明。

frp 采用 Golang 编写,支持跨平台,仅需下载对应平台的二进制文件即可执行,没有额外依赖。

系统需求

由于采用 Golang 编写,所以系统需求和最新的 Golang 对系统和平台的要求一致,具体可以参考 Golang System requirements

下载

目前可以在 Github 的 Release 页面中下载到最新版本的客户端和服务端二进制文件,所有文件被打包在一个压缩包中。

部署

解压缩下载的压缩包,将其中的 frpc 拷贝到内网服务所在的机器上,将 frps 拷贝到具有公网 IP 的机器上,放置在任意目录。

开始使用!

编写配置文件,先通过 ./frps -c ./frps.ini 启动服务端,再通过 ./frpc -c ./frpc.ini 启动客户端。如果需要在后台长期运行,建议结合其他工具使用,例如 systemdsupervisor

如果是 Windows 用户,需要在 cmd 终端中执行命令。

概念

一些概念,理解它们有助于您更好地了解和使用 frp。

原理

frp 主要由 客户端(frpc)服务端(frps) 组成,服务端通常部署在具有公网 IP 的机器上,客户端通常部署在需要穿透的内网服务所在的机器上。

内网服务由于没有公网 IP,不能被非局域网内的其他用户访问。

用户通过访问服务端的 frps,由 frp 负责根据请求的端口或其他信息将请求路由到对应的内网机器,从而实现通信。

代理

在 frp 中一个代理对应一个需要暴露的内网服务。一个客户端支持同时配置多个代理。

代理类型

frp 支持多种代理类型来适配不同的使用场景。

类型 描述
tcp 单纯的 TCP 端口映射,服务端会根据不同的端口路由到不同的内网服务。
udp 单纯的 UDP 端口映射,服务端会根据不同的端口路由到不同的内网服务。
http 针对 HTTP 应用定制了一些额外的功能,例如修改 Host Header,增加鉴权。
https 针对 HTTPS 应用定制了一些额外的功能。
stcp 安全的 TCP 内网代理,需要在被访问者和访问者的机器上都部署 frpc,不需要在服务端暴露端口。
sudp 安全的 UDP 内网代理,需要在被访问者和访问者的机器上都部署 frpc,不需要在服务端暴露端口。
xtcp 点对点内网穿透代理,功能同 stcp,但是流量不需要经过服务器中转。
tcpmux 支持服务端 TCP 端口的多路复用,通过同一个端口访问不同的内网服务。

示例

这里包括多个常见的使用场景和配置示例,你可以用来亲自部署和体验这些示例。

通过 SSH 访问内网机器

这个示例通过简单配置 TCP 类型的代理让用户访问到内网的服务器。

  1. 在具有公网 IP 的机器上部署 frps,修改 frps.ini 文件,这里使用了最简化的配置,设置了 frp 服务器用户接收客户端连接的端口:

    [common]
    bind_port = 7000
    
  2. 在需要被访问的内网机器上(SSH 服务通常监听在 22 端口)部署 frpc,修改 frpc.ini 文件,假设 frps 所在服务器的公网 IP 为 x.x.x.x:

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [ssh]
    type = tcp
    local_ip = 127.0.0.1
    local_port = 22
    remote_port = 6000
    

    local_iplocal_port 配置为本地需要暴露到公网的服务地址和端口。remote_port 表示在 frp 服务端监听的端口,访问此端口的流量将会被转发到本地服务对应的端口。

  3. 分别启动 frps 和 frpc。

  4. 通过 SSH 访问内网机器,假设用户名为 test:

    ssh -oPort=6000 test@x.x.x.x

    frp 会将请求 x.x.x.x:6000 的流量转发到内网机器的 22 端口。

通过自定义域名访问内网的 Web 服务

这个示例通过简单配置 HTTP 类型的代理让用户访问到内网的 Web 服务。

HTTP 类型的代理相比于 TCP 类型,不仅在服务端只需要监听一个额外的端口 vhost_http_port 用于接收 HTTP 请求,还额外提供了基于 HTTP 协议的诸多功能。

  1. 修改 frps.ini 文件,设置监听 HTTP 请求端口为 8080:

    [common]
    bind_port = 7000
    vhost_http_port = 8080
    
  2. 修改 frpc.ini 文件,假设 frps 所在的服务器的 IP 为 x.x.x.x,local_port 为本地机器上 Web 服务监听的端口, 绑定自定义域名为 custom_domains

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [web]
    type = http
    local_port = 80
    custom_domains = www.yourdomain.com
    
    [web2]
    type = http
    local_port = 8080
    custom_domains = www.yourdomain2.com
    
  3. 分别启动 frps 和 frpc。

  4. www.yourdomain.comwww.yourdomain2.com 的域名 A 记录解析到 IP x.x.x.x,如果服务器已经有对应的域名,也可以将 CNAME 记录解析到服务器原先的域名。或者可以通过修改 HTTP 请求的 Host 字段来实现同样的效果。

  5. 通过浏览器访问 http://www.yourdomain.com:8080 即可访问到处于内网机器上 80 端口的服务,访问 http://www.yourdomain2.com:8080 则访问到内网机器上 8080 端口的服务。

转发 DNS 查询请求

这个示例通过简单配置 UDP 类型的代理转发 DNS 查询请求。

DNS 查询请求通常使用 UDP 协议,frp 支持对内网 UDP 服务的穿透,配置方式和 TCP 基本一致。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. frpc.ini 内容如下:

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [dns]
    type = udp
    local_ip = 8.8.8.8
    local_port = 53
    remote_port = 6000
    

    这里反代了 Google 的 DNS 查询服务器的地址,仅仅用于测试 UDP 代理,并无实际意义。

  3. 分别启动 frps 和 frpc。

  4. 通过 dig 测试 UDP 包转发是否成功,预期会返回 www.baidu.com 域名的解析结果。

    dig @x.x.x.x -p 6000 www.baidu.com

转发 Unix 域套接字

这个示例通过配置 Unix域套接字客户端插件来通过 TCP 端口访问内网的 Unix域套接字服务,例如 Docker Daemon。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. frpc.ini 内容如下:

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [unix_domain_socket]
    type = tcp
    remote_port = 6000
    plugin = unix_domain_socket
    plugin_unix_path = /var/run/docker.sock
    
  3. 分别启动 frps 和 frpc。

  4. 通过 curl 命令查看 docker 版本信息

    curl http://x.x.x.x:6000/version

对外提供简单的文件访问服务

这个示例通过配置 static_file 客户端插件来将本地文件暴露在公网上供其他人访问。

通过 static_file 插件可以对外提供一个简单的基于 HTTP 的文件访问服务。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. frpc.ini 内容如下:

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [test_static_file]
    type = tcp
    remote_port = 6000
    plugin = static_file
    # 要对外暴露的文件目录
    plugin_local_path = /tmp/file
    # 用户访问 URL 中会被去除的前缀,保留的内容即为要访问的文件路径
    plugin_strip_prefix = static
    plugin_http_user = abc
    plugin_http_passwd = abc
    
  3. 分别启动 frps 和 frpc。

  4. 通过浏览器访问 http://x.x.x.x:6000/static/ 来查看位于 /tmp/file 目录下的文件,会要求输入已设置好的用户名和密码。

为本地 HTTP 服务启用 HTTPS

通过 https2http 插件可以让本地 HTTP 服务转换成 HTTPS 服务对外提供。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. frpc.ini 内容如下:

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [test_htts2http]
    type = https
    custom_domains = test.yourdomain.com
    
    plugin = https2http
    plugin_local_addr = 127.0.0.1:80
    
    # HTTPS 证书相关的配置
    plugin_crt_path = ./server.crt
    plugin_key_path = ./server.key
    plugin_host_header_rewrite = 127.0.0.1
    plugin_header_X-From-Where = frp
    
  3. 分别启动 frps 和 frpc。

  4. 通过浏览器访问 https://test.yourdomain.com

安全地暴露内网服务

这个示例将会创建一个只有自己能访问到的 SSH 服务代理。

对于某些服务来说如果直接暴露于公网上将会存在安全隐患。

使用 stcp(secret tcp) 类型的代理可以避免让任何人都能访问到要穿透的服务,但是访问者也需要运行另外一个 frpc 客户端。

  1. frps.ini 内容如下:

    [common]
    bind_port = 7000
    
  2. 在需要暴露到内网的机器上部署 frpc,且配置如下:

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [secret_ssh]
    type = stcp
    # 只有 sk 一致的用户才能访问到此服务
    sk = abcdefg
    local_ip = 127.0.0.1
    local_port = 22
    
  3. 在想要访问内网服务的机器上也部署 frpc,且配置如下:

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [secret_ssh_visitor]
    type = stcp
    # stcp 的访问者
    role = visitor
    # 要访问的 stcp 代理的名字
    server_name = secret_ssh
    sk = abcdefg
    # 绑定本地端口用于访问 SSH 服务
    bind_addr = 127.0.0.1
    bind_port = 6000
    
  4. 通过 SSH 访问内网机器,假设用户名为 test:

    ssh -oPort=6000 test@127.0.0.1

点对点内网穿透

这个示例将会演示一种不通过服务器中转流量的方式来访问内网服务。

frp 提供了一种新的代理类型 xtcp 用于应对在希望传输大量数据且流量不经过服务器的场景。

使用方式同 stcp 类似,需要在两边都部署上 frpc 用于建立直接的连接。

目前处于开发的初级阶段,并不能穿透所有类型的 NAT 设备,所以穿透成功率较低。穿透失败时可以尝试 stcp 的方式。

  1. frps.ini 内容如下,需要额外配置监听一个 UDP 端口用于支持该类型的客户端:

    [common]
    bind_port = 7000
    bind_udp_port = 7000
    
  2. 在需要暴露到内网的机器上部署 frpc,且配置如下:

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [p2p_ssh]
    type = xtcp
    # 只有 sk 一致的用户才能访问到此服务
    sk = abcdefg
    local_ip = 127.0.0.1
    local_port = 22
    
  3. 在想要访问内网服务的机器上也部署 frpc,且配置如下:

    [common]
    server_addr = x.x.x.x
    server_port = 7000
    
    [p2p_ssh_visitor]
    type = xtcp
    # xtcp 的访问者
    role = visitor
    # 要访问的 xtcp 代理的名字
    server_name = p2p_ssh
    sk = abcdefg
    # 绑定本地端口用于访问 ssh 服务
    bind_addr = 127.0.0.1
    bind_port = 6000
    
  4. 通过 SSH 访问内网机器,假设用户名为 test:

    ssh -oPort=6000 test@127.0.0.1

参考

服务端配置

frp 服务端详细配置说明。

基础配置

参数 类型 说明 默认值 可选值 备注
bind_addr string 服务端监听地址 0.0.0.0
bind_port int 服务端监听端口 7000 接收 frpc 的连接
bind_udp_port int 服务端监听 UDP 端口 0 用于辅助创建 P2P 连接
kcp_bind_port int 服务端监听 KCP 协议端口 0 用于接收采用 KCP 连接的 frpc
proxy_bind_addr string 代理监听地址 同 bind_addr 可以使代理监听在不同的网卡地址
log_file string 日志文件地址 ./frps.log 如果设置为 console,会将日志打印在标准输出中
log_level string 日志等级 info trace, debug, info, warn, error
log_max_days int 日志文件保留天数 3
disable_log_color bool 禁用标准输出中的日志颜色 false
detailed_errors_to_client bool 服务端返回详细错误信息给客户端 true
heart_beat_timeout int 服务端和客户端心跳连接的超时时间 90 单位:秒
user_conn_timeout int 用户建立连接后等待客户端响应的超时时间 10 单位:秒
udp_packet_size int 代理 UDP 服务时支持的最大包长度 1500 服务端和客户端的值需要一致
tls_cert_file string TLS 服务端证书文件路径
tls_key_file string TLS 服务端密钥文件路径
tls_trusted_ca_file string TLS CA 证书路径

权限验证

参数 类型 说明 默认值 可选值 备注
authentication_method string 鉴权方式 token token, oidc
authenticate_heartbeats bool 开启心跳消息鉴权 false
authenticate_new_work_conns bool 开启建立工作连接的鉴权 false
token string 鉴权使用的 token 值 客户端需要设置一样的值才能鉴权通过
oidc_issuer string oidc_issuer
oidc_audience string oidc_audience
oidc_skip_expiry_check bool oidc_skip_expiry_check
oidc_skip_issuer_check bool oidc_skip_issuer_check

管理配置

参数 类型 说明 默认值 可选值 备注
allow_ports string 允许代理绑定的服务端端口 格式为 1000-2000,2001,3000-4000
max_pool_count int 最大连接池大小 5
max_ports_per_client int 限制单个客户端最大同时存在的代理数 0 0 表示没有限制
tls_only bool 只接受启用了 TLS 的客户端连接 false

Dashboard, 监控

参数 类型 说明 默认值 可选值 备注
dashboard_addr string 启用 Dashboard 监听的本地地址 0.0.0.0
dashboard_port int 启用 Dashboard 监听的本地端口 0
dashboard_user string HTTP BasicAuth 用户名
dashboard_pwd string HTTP BasicAuth 密码
enable_prometheus bool 是否提供 Prometheus 监控接口 false 需要同时启用了 Dashboard 才会生效
asserts_dir string 静态资源目录 Dashboard 使用的资源默认打包在二进制文件中,通过指定此参数使用自定义的静态资源

HTTP & HTTPS

参数 类型 说明 默认值 可选值 备注
vhost_http_port int 为 HTTP 类型代理监听的端口 0 启用后才支持 HTTP 类型的代理,默认不启用
vhost_https_port int 为 HTTPS 类型代理监听的端口 0 启用后才支持 HTTPS 类型的代理,默认不启用
vhost_http_timeout int HTTP 类型代理在服务端的 ResponseHeader 超时时间 60
subdomain_host string 二级域名后缀
custom_404_page string 自定义 404 错误页面地址

TCPMUX

参数 类型 说明 默认值 可选值 备注
tcpmux_httpconnect_port int 为 TCPMUX 类型代理监听的端口 0 启用后才支持 TCPMUX 类型的代理,默认不启用

客户端配置

frp 客户端的详细配置说明。

基础配置

参数 类型 说明 默认值 可选值 备注
server_addr string 连接服务端的地址 0.0.0.0
server_port int 连接服务端的端口 7000
http_proxy string 连接服务端使用的代理地址 格式为 {protocol}://user:passwd@192.168.1.128:8080 protocol 目前支持 http、socks5、ntlm
log_file string 日志文件地址 ./frpc.log 如果设置为 console,会将日志打印在标准输出中
log_level string 日志等级 info trace, debug, info, warn, error
log_max_days int 日志文件保留天数 3
disable_log_color bool 禁用标准输出中的日志颜色 false
pool_count int 连接池大小 0
user string 用户名 设置此参数后,代理名称会被修改为 {user}.{proxyName},避免代理名称和其他用户冲突
dns_server string 使用 DNS 服务器地址 默认使用系统配置的 DNS 服务器,指定此参数可以强制替换为自定义的 DNS 服务器地址
login_fail_exit bool 第一次登陆失败后是否退出 true
protocol string 连接服务端的通信协议 tcp tcp, kcp, websocket
tls_enable bool 启用 TLS 协议加密连接 false
tls_cert_file string TLS 客户端证书文件路径
tls_key_file string TLS 客户端密钥文件路径
tls_trusted_ca_file string TLS CA 证书路径
tls_server_name string TLS Server 名称 为空则使用 server_addr
heartbeat_interval int 向服务端发送心跳包的间隔时间 30
heartbeat_timeout int 和服务端心跳的超时时间 90
udp_packet_size int 代理 UDP 服务时支持的最大包长度 1500 服务端和客户端的值需要一致
start string 指定启用部分代理 当配置了较多代理,但是只希望启用其中部分时可以通过此参数指定,默认为全部启用

权限验证

参数 类型 说明 默认值 可选值 备注
authentication_method string 鉴权方式 token token, oidc 需要和服务端一致
authenticate_heartbeats bool 开启心跳消息鉴权 false 需要和服务端一致
authenticate_new_work_conns bool 开启建立工作连接的鉴权 false 需要和服务端一致
token string 鉴权使用的 token 值 需要和服务端设置一样的值才能鉴权通过
oidc_client_id string oidc_client_id
oidc_client_secret string oidc_client_secret
oidc_audience string oidc_audience
oidc_token_endpoint_url string oidc_token_endpoint_url

UI

参数 类型 说明 默认值 可选值 备注
admin_addr string 启用 AdminUI 监听的本地地址 0.0.0.0
admin_port int 启用 AdminUI 监听的本地端口 0
admin_user string HTTP BasicAuth 用户名
admin_pwd string HTTP BasicAuth 密码
asserts_dir string 静态资源目录 AdminUI 使用的资源默认打包在二进制文件中,通过指定此参数使用自定义的静态资源

代理配置

frp 代理的详细配置说明。

通用配置

通用配置是指不同类型的代理共同使用的一些配置参数。

基础配置

参数 类型 说明 是否必须 默认值 可选值 备注
type string 代理类型 tcp tcp, udp, http, https, stcp, sudp, xtcp, tcpmux
use_encryption bool 是否启用加密功能 false 启用后该代理和服务端之间的通信内容都会被加密传输
use_compression bool 是否启用压缩功能 false 启用后该代理和服务端之间的通信内容都会被压缩传输
proxy_protocol_version string 启用 proxy protocol 协议的版本 v1, v2 如果启用,则 frpc 和本地服务建立连接后会发送 proxy protocol 的协议,包含了原请求的 IP 地址和端口等内容
bandwidth_limit string 设置单个 proxy 的带宽限流 单位为 MB 或 KB,0 表示不限制,如果启用,会作用于对应的 frpc

本地服务配置

local_ipplugin 的配置必须配置一个,且只能生效一个,如果配置了 plugin,则 local_ip 配置无效。

参数 类型 说明 是否必须 默认值 可选值 备注
local_ip string 本地服务 IP 127.0.0.1 需要被代理的本地服务的 IP 地址,可以为所在 frpc 能访问到的任意 IP 地址
local_port int 本地服务端口 配合 local_ip
plugin string 客户端插件名称 见客户端插件的功能说明 用于扩展 frpc 的能力,能够提供一些简单的本地服务,如果配置了 plugin,则 local_ip 和 local_port 无效,两者只能配置一个
plugin_params map 客户端插件参数 map 结构,key 需要都以 "plugin_" 开头,每一个 plugin 需要的参数也不一样,具体见客户端插件参数中的内容

负载均衡和健康检查

参数 类型 说明 是否必须 默认值 可选值 备注
group string 负载均衡分组名称 用户请求会以轮询的方式发送给同一个 group 中的代理
group_key string 负载均衡分组密钥 用于对负载均衡分组进行鉴权,group_key 相同的代理才会被加入到同一个分组中
health_check_type string 健康检查类型 tcp,http 配置后启用健康检查功能,tcp 是连接成功则认为服务健康,http 要求接口返回 2xx 的状态码则认为服务健康
health_check_timeout_s int 健康检查超时时间(秒) 3 执行检查任务的超时时间
health_check_max_failed int 健康检查连续错误次数 1 连续检查错误多少次认为服务不健康
health_check_interval_s int 健康检查周期(秒) 10 每隔多长时间进行一次健康检查
health_check_url string 健康检查的 HTTP 接口 如果 health_check_type 类型是 http,则需要配置此参数,指定发送 http 请求的 url,例如 "/health"

TCP

参数 类型 说明 是否必须 默认值 可选值 备注
remote_port int 服务端绑定的端口 用户访问此端口的请求会被转发到 local_ip:local_port

UDP

参数 类型 说明 是否必须 默认值 可选值 备注
remote_port int 服务端绑定的端口 用户访问此端口的请求会被转发到 local_ip:local_port

HTTP

custom_domainssubdomain 必须要配置其中一个,两者可以同时生效。

参数 类型 说明 是否必须 默认值 可选值 备注
custom_domains []string 服务器绑定自定义域名 是(和 subdomain 两者必须配置一个) 用户通过 vhost_http_port 访问的 HTTP 请求如果 Host 在 custom_domains 配置的域名中,则会被路由到此代理配置的本地服务
subdomain string 自定义子域名 是(和 custom_domains 两者必须配置一个) 和 custom_domains 作用相同,但是只需要指定子域名前缀,会结合服务端的 subdomain_host 生成最终绑定的域名
locations []string URL 路由配置 采用最大前缀匹配的规则,用户请求匹配响应的 location 配置,则会被路由到此代理
http_user string 用户名 如果配置此参数,暴露出去的 HTTP 服务需要采用 Basic Auth 的鉴权才能访问
http_pwd string 密码 结合 http_user 使用
host_header_rewrite string 替换 Host header 替换发送到本地服务 HTTP 请求中的 Host 字段
headers map 替换 header map 中的 key 是要替换的 header 的 key,value 是替换后的内容

HTTPS

custom_domainssubdomain 必须要配置其中一个,两者可以同时生效。

参数 类型 说明 是否必须 默认值 可选值 备注
custom_domains []string 服务器绑定自定义域名 是(和 subdomain 两者必须配置一个) 用户通过 vhost_http_port 访问的 HTTP 请求如果 Host 在 custom_domains 配置的域名中,则会被路由到此代理配置的本地服务
subdomain string 自定义子域名 是(和 custom_domains 两者必须配置一个) 和 custom_domains 作用相同,但是只需要指定子域名前缀,会结合服务端的 subdomain_host 生成最终绑定的域名

STCP

参数 类型 说明 是否必须 默认值 可选值 备注
role string 角色 server server,visitor server 表示服务端,visitor 表示访问端
sk string 密钥 服务端和访问端的密钥需要一致,访问端才能访问到服务端

SUDP

参数 类型 说明 是否必须 默认值 可选值 备注
role string 角色 server server,visitor server 表示服务端,visitor 表示访问端
sk string 密钥 服务端和访问端的密钥需要一致,访问端才能访问到服务端

XTCP

参数 类型 说明 是否必须 默认值 可选值 备注
role string 角色 server server,visitor server 表示服务端,visitor 表示访问端
sk string 密钥 服务端和访问端的密钥需要一致,访问端才能访问到服务端

ubuntu 防止SSH暴力登录攻击

最近观察服务器的认证日志,发现有些国外的 IP 地址,多次尝试破解服务器的密码进行登录。于是希望能将多次尝试 SSH 登录失败的 IP 阻止掉。

查看日志文件:

sudo tail -f /var/log/auth.log

看到很多如下的日志:

来统计一下有多少人在暴力破解 root 密码

sudo grep "Failed password for root" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -nr | more
   3579 111.198.159.85
   1185 111.229.204.86
    457 121.89.198.64
    109 112.85.236.98
    106 36.94.17.242
     99 45.141.84.126
     89 129.28.163.90
     83 111.231.87.10
     77 64.225.53.232
     77 122.155.202.93
     72 64.225.126.22
     72 113.57.170.50
     72 103.117.120.47
     71 45.232.244.5
     71 138.197.149.97
     70 134.175.154.93
     67 159.65.100.44
     67 120.131.13.186
     67 104.248.205.67
     64 152.32.222.192
     61 150.136.40.83
     59 188.170.13.225
     59 178.128.14.102

如果已经禁用了 root 登录,则看一下暴力猜用户名的统计信息

sudo grep "Failed password for invalid user" /var/log/auth.log | awk '{print $13}' | sort | uniq -c | sort -nr | more
   1812 111.198.159.85
    645 111.229.204.86
    275 45.141.84.126
     85 36.94.17.242
     85 112.85.236.98
     56 111.231.87.10
     55 172.103.3.143
     52 211.253.26.117
     51 129.28.163.90
     50 134.175.154.93

为了防范于未然,我们可以做些配置,让服务器更加安全。

下面的三个方法,可以完全使用,也可以部分使用。一般建议使用其中的第一条跟第三条。

  1. 修改 SSH 端口,禁止 root 登陆

修改 /etc/ssh/sshd_config 文件

sudo vim /etc/ssh/sshd_config
 
Port 1234 # 一个别人猜不到的端口号
PermitRootLogin no
 
sudo service sshd restart
  1. 禁用密码登陆,使用 RSA 私钥登录

如果服务器只允许使用私钥登录的,但是如果想在别的电脑上临时 SSH 上来,又没带私钥文件的情况下,就很麻烦。所以还是保留密码验证登录。不管怎样,这一条还是先列出来

# 在客户端生成密钥
ssh-keygen -t rsa
 
# 把公钥拷贝至服务器
ssh-copy-id -i .ssh/id_rsa.pub server
 
# 也可以手动将.shh/id_rsa.pub拷贝至服务器用户目录的.ssh中,记得修改访问权限
# $ scp .shh/id_rsa.pub server:~/.ssh
 
# 在服务器中
cd ./.ssh/
 
mv id_rsa.pub authorized_keys
 
chmod 400 authorized_keys
 
vim /etc/ssh/sshd_config
 
RSAAuthentication yes #RSA认证
PubkeyAuthentication yes #开启公钥验证
AuthorizedKeysFile .ssh/authorized_keys #验证文件路径
PasswordAuthentication no #禁止密码认证
PermitEmptyPasswords no #禁止空密码
UsePAM no #禁用PAM
 
 
# 最后保存,重启
sudo service sshd restart
  1. 安装 denyhosts

denyhostsPython 语言写的一个程序,它会分析 sshd 的日志文件,当发现重复的失败登录时就会记录 IP/etc/hosts.deny 文件,从而达到自动屏 IP 的功能。现今 denyhosts 在各个发行版软件仓库里都有。

注意在 ubuntu 16.04 系统上,如果通过远程的 SSH 登录到服务器上执行安装命令的话,会由于默认情况下 RESET_ON_SUCCESS = yes #如果一个ip登陆成功后,失败的登陆计数是否重置为0 这部分,默认情况下是关闭的。而如果恰好我们又出现自己输入的错误密码错误累计次数超过 5 次的情况(即使后面有成功登录的记录也不行),会导致我们自己当前登录的地址也被阻止的情况。这种情况发生之后,会导致我们自己无法控制服务器(这个阻塞是在 iptables 层阻塞的,如果要恢复,在 iptables 中删除已经添加的记录才可以)。解决办法就是换一个新的 IP 地址登录服务器,然后修改 RESET_ON_SUCCESS 这个参数,并重启 denyhosts 服务。如果是阿里云或者腾讯云的服务器,可以尝试从他们网站上提供的网页版本的 Shell 进行操作。

对于 ubuntu 16.04 系统,建议使用如下方式进行安装:

#创建执行脚本
touch ~/install.sh
 
#创建执行安装命令,整个过程不中断连续执行,如果不使用脚本,执行到这里,可能SSH就已经被阻断了
#安装完成后,denyhosts的服务就已经开始运行了,此时可能已经设置了iptables了
echo "sudo apt-get install denyhosts" >> ~/install.sh 
 
#创建修改配置文件的命令
echo "sudo sed -i 's/^#RESET_ON_SUCCESS/RESET_ON_SUCCESS/g' /etc/denyhosts.conf" >> ~/install.sh
 
#创建重启服务的命令
echo "sudo service denyhosts restart" >> ~/install.sh
 
#执行我们刚刚的安装脚本
sudo bash ~/install.sh

默认配置就能很好的工作,如要个性化设置可以修改 /etc/denyhosts.conf

sudo vim /etc/denyhosts.conf
 
SECURE_LOG = /var/log/auth.log #ssh 日志文件,它是根据这个文件来判断的。
HOSTS_DENY = /etc/hosts.deny #控制用户登陆的文件
PURGE_DENY = #过多久后清除已经禁止的,空表示永远不解禁
BLOCK_SERVICE = sshd #禁止的服务名,如还要添加其他服务,只需添加逗号跟上相应的服务即可
DENY_THRESHOLD_INVALID = 5 #允许无效用户失败的次数
DENY_THRESHOLD_VALID = 10 #允许普通用户登陆失败的次数
DENY_THRESHOLD_ROOT = 1 #允许root登陆失败的次数
DENY_THRESHOLD_RESTRICTED = 1
WORK_DIR = /var/lib/denyhosts #运行目录
SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES
HOSTNAME_LOOKUP=YES #是否进行域名反解析
LOCK_FILE = /var/run/denyhosts.pid #程序的进程ID
ADMIN_EMAIL = root@localhost #管理员邮件地址,它会给管理员发邮件
SMTP_HOST = localhost
SMTP_PORT = 25
SMTP_FROM = DenyHosts <nobody@localhost>
SMTP_SUBJECT = DenyHosts Report
AGE_RESET_VALID=5d #用户的登录失败计数会在多久以后重置为0,(h表示小时,d表示天,m表示月,w表示周,y表示年)
AGE_RESET_ROOT=25d
AGE_RESET_RESTRICTED=25d
AGE_RESET_INVALID=10d
RESET_ON_SUCCESS = yes #如果一个ip登陆成功后,失败的登陆计数是否重置为0
DAEMON_LOG = /var/log/denyhosts #自己的日志文件
DAEMON_SLEEP = 30s #当以后台方式运行时,每读一次日志文件的时间间隔。
DAEMON_PURGE = 1h #当以后台方式运行时,清除机制在 HOSTS_DENY 中终止旧条目的时间间隔,这个会影响PURGE_DENY的间隔。

查看 /etc/hosts.deny 发现里面已经有 3 条记录。

sudo cat /etc/hosts.deny | wc -l
3

目前 ubuntu 16.04 系统源里的 denyhosts 存在一个 BUG ,就是系统重启之后, iptables 中的拦截设置没有恢复。具体的讨论以及描述,参考 Iptables not persistent,代码应该已经增加了,目前还没合并到主分支。

参考链接

AES五种加密模式(CBC、ECB、CTR、OCF、CFB)

AES五种加密模式(CBC、ECB、CTR、OCF、CFB)

分组密码有五种工作体制:

  1. 电码本模式(Electronic Codebook Book (ECB));
  2. 密码分组链接模式(Cipher Block Chaining (CBC));
  3. 计算器模式(Counter (CTR));
  4. 密码反馈模式(Cipher FeedBack (CFB));
  5. 输出反馈模式(Output FeedBack (OFB))。

以下逐一介绍一下:

1.电码本模式(Electronic Codebook Book (ECB)

这种模式是将整个明文分成若干段相同的小段,然后对每一小段进行加密。

2.密码分组链接模式(Cipher Block Chaining (CBC))

这种模式是先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密。

3.计算器模式(Counter (CTR))

计算器模式不常见,在CTR模式中, 有一个自增的算子,这个算子用密钥加密之后的输出和明文异或的结果得到密文,相当于一次一密。这种加密方式简单快速,安全可靠,而且可以并行加密,但是在计算器不能维持很长的情况下,密钥只能使用一次。CTR的示意图如下所示:

4.密码反馈模式(Cipher FeedBack (CFB))

这种模式较复杂。

5.输出反馈模式(Output FeedBack (OFB))

这种模式较复杂。

以下附上C++源代码:

/**
*@autho stardust
*@time 2013-10-10
*@param 实现AES五种加密模式的测试
*/
#include <iostream>
using namespace std;

//加密编码过程函数,16位1和0
int dataLen = 16;   //需要加密数据的长度
int encLen = 4;     //加密分段的长度
int encTable[4] = {1,0,1,0};  //置换表
int data[16] = {1,0,0,1,0,0,0,1,1,1,1,1,0,0,0,0}; //明文
int ciphertext[16]; //密文

//切片加密函数
void encode(int arr[])
{
    for(int i=0;i<encLen;i++)
    {
        arr[i] = arr[i] ^ encTable[i];
    }
}

//电码本模式加密,4位分段
void ECB(int arr[])
{
    //数据明文切片
    int a[4][4];
    int dataCount = 0;  //位置变量
    for(int k=0;k<4;k++)
    {
        for(int t=0;t<4;t++)
        {
            a[k][t] = data[dataCount];
            dataCount++;
        }
    }
    dataCount = 0;//重置位置变量
    for(int i=0;i<dataLen;i=i+encLen)
    {
        int r = i/encLen;//行
        int l = 0;//列
        int encQue[4]; //编码片段
        for(int j=0;j<encLen;j++)
        {
            encQue[j] = a[r][l];
            l++;
        }
        encode(encQue); //切片加密
        //添加到密文表中
        for(int p=0;p<encLen;p++)
        {
            ciphertext[dataCount] = encQue[p];
            dataCount++;
        }
    }
    cout<<"ECB加密的密文为:"<<endl;
    for(int t1=0;t1<dataLen;t1++) //输出密文
    {
        if(t1!=0 && t1%4==0)
            cout<<endl;
        cout<<ciphertext[t1]<<" ";
    }
    cout<<endl;
    cout<<"---------------------------------------------"<<endl;
}

//CBC
//密码分组链接模式,4位分段
void CCB(int arr[])
{
    //数据明文切片
    int a[4][4];
    int dataCount = 0;  //位置变量
    for(int k=0;k<4;k++)
    {
        for(int t=0;t<4;t++)
        {
            a[k][t] = data[dataCount];
            dataCount++;
        }
    }
    dataCount = 0;//重置位置变量

    int init[4] = {1,1,0,0};  //初始异或运算输入
    //初始异或运算
    for(int i=0;i<dataLen;i=i+encLen)
    {
        int r = i/encLen;//行
        int l = 0;//列
        int encQue[4]; //编码片段
        //初始化异或运算
        for(int k=0;k<encLen;k++)
        {
            a[r][k] = a[r][k] ^ init[k];
        }
         //与Key加密的单切片
        for(int j=0;j<encLen;j++)
        {
            encQue[j] = a[r][j];
        }
        encode(encQue); //切片加密
        //添加到密文表中
        for(int p=0;p<encLen;p++)
        {
            ciphertext[dataCount] = encQue[p];
            dataCount++;
        }
        //变换初始输入
        for(int t=0;t<encLen;t++)
        {
            init[t] = encQue[t];
        }
    }


    cout<<"CCB加密的密文为:"<<endl;
    for(int t1=0;t1<dataLen;t1++) //输出密文
    {
        if(t1!=0 && t1%4==0)
            cout<<endl;
        cout<<ciphertext[t1]<<" ";
    }
    cout<<endl;
    cout<<"---------------------------------------------"<<endl;
}

//CTR
//计算器模式,4位分段
void CTR(int arr[])
{
    //数据明文切片
    int a[4][4];
    int dataCount = 0;  //位置变量
    for(int k=0;k<4;k++)
    {
        for(int t=0;t<4;t++)
        {
            a[k][t] = data[dataCount];
            dataCount++;
        }
    }
    dataCount = 0;//重置位置变量

    int init[4][4] = {{1,0,0,0},{0,0,0,1},{0,0,1,0},{0,1,0,0}};  //算子表
    int l = 0; //明文切片表列
    //初始异或运算
    for(int i=0;i<dataLen;i=i+encLen)
    {
        int r = i/encLen;//行
        int encQue[4]; //编码片段
        //将算子切片
        for(int t=0;t<encLen;t++)
        {
            encQue[t] = init[r][t];
        }
        encode(encQue); //算子与key加密
        //最后的异或运算
        for(int k=0;k<encLen;k++)
        {
            encQue[k] = encQue[k] ^ a[l][k];
        }
        l++;

        //添加到密文表中
        for(int p=0;p<encLen;p++)
        {
            ciphertext[dataCount] = encQue[p];
            dataCount++;
        }
    }


    cout<<"CTR加密的密文为:"<<endl;
    for(int t1=0;t1<dataLen;t1++) //输出密文
    {
        if(t1!=0 && t1%4==0)
            cout<<endl;
        cout<<ciphertext[t1]<<" ";
    }
    cout<<endl;
    cout<<"---------------------------------------------"<<endl;
}

//CFB
//密码反馈模式,4位分段
void CFB(int arr[])
{
    //数据明文切片,切成2 * 8 片
    int a[8][2];
    int dataCount = 0;  //位置变量
    for(int k=0;k<8;k++)
    {
        for(int t=0;t<2;t++)
        {
            a[k][t] = data[dataCount];
            dataCount++;
        }
    }
    dataCount = 0;  //恢复初始化设置
    int lv[4] = {1,0,1,1};  //初始设置的位移变量
    int encQue[2]; //K的高两位
    int k[4]; //K

    for(int i=0;i<2 * encLen;i++) //外层加密循环
    {
        //产生K
        for(int vk=0;vk<encLen;vk++)
        {
            k[vk] = lv[vk];
        }
        encode(k);
        for(int k2=0;k2<2;k2++)
        {
            encQue[k2] = k[k2];
        }
        //K与数据明文异或产生密文
        for(int j=0;j<2;j++)
        {
            ciphertext[dataCount] = a[dataCount/2][j] ^ encQue[j];
            dataCount++;
        }
        //lv左移变换
        lv[0] = lv[2];
        lv[1] = lv[3];
        lv[2] = ciphertext[dataCount-2];
        lv[3] = ciphertext[dataCount-1];
    }

    cout<<"CFB加密的密文为:"<<endl;
    for(int t1=0;t1<dataLen;t1++) //输出密文
    {
        if(t1!=0 && t1%4==0)
            cout<<endl;
        cout<<ciphertext[t1]<<" ";
    }
    cout<<endl;
    cout<<"---------------------------------------------"<<endl;
}

//OFB
//输出反馈模式,4位分段
void OFB(int arr[])
{
    //数据明文切片,切成2 * 8 片
    int a[8][2];
    int dataCount = 0;  //位置变量
    for(int k=0;k<8;k++)
    {
        for(int t=0;t<2;t++)
        {
            a[k][t] = data[dataCount];
            dataCount++;
        }
    }
    dataCount = 0;  //恢复初始化设置
    int lv[4] = {1,0,1,1};  //初始设置的位移变量
    int encQue[2]; //K的高两位
    int k[4]; //K

    for(int i=0;i<2 * encLen;i++) //外层加密循环
    {
        //产生K
        for(int vk=0;vk<encLen;vk++)
        {
            k[vk] = lv[vk];
        }
        encode(k);
        for(int k2=0;k2<2;k2++)
        {
            encQue[k2] = k[k2];
        }
        //K与数据明文异或产生密文
        for(int j=0;j<2;j++)
        {
            ciphertext[dataCount] = a[dataCount/2][j] ^ encQue[j];
            dataCount++;
        }
        //lv左移变换
        lv[0] = lv[2];
        lv[1] = lv[3];
        lv[2] = encQue[0];
        lv[3] = encQue[1];
    }

    cout<<"CFB加密的密文为:"<<endl;
    for(int t1=0;t1<dataLen;t1++) //输出密文
    {
        if(t1!=0 && t1%4==0)
            cout<<endl;
        cout<<ciphertext[t1]<<" ";
    }
    cout<<endl;
    cout<<"---------------------------------------------"<<endl;
}


void printData()
{
    cout<<"以下示范AES五种加密模式的测试结果:"<<endl;
    cout<<"---------------------------------------------"<<endl;
    cout<<"明文为:"<<endl;
    for(int t1=0;t1<dataLen;t1++) //输出密文
    {
        if(t1!=0 && t1%4==0)
            cout<<endl;
        cout<<data[t1]<<" ";
    }
    cout<<endl;
    cout<<"---------------------------------------------"<<endl;
}
int main()
{
    printData();
    ECB(data);
    CCB(data);
    CTR(data);
    CFB(data);
    OFB(data);
    return 0;
}