查看是否支持 SSL

首先在 MySQL 上执行如下命令, 查询是否 MySQL 支持 SSL:

1
2
3
4
5
6
7
mysql> SHOW VARIABLES LIKE 'have_ssl';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_ssl | YES |
+---------------+-------+
1 row in set (0.02 sec)

have_sslYES 时, 表示此时 MySQL 服务已经支持 SSL 了. 如果是 DESABLE, 则需要在启动 MySQL 服务时, 使能 SSL 功能.

使用 OpenSSL 创建 SSL 证书和私钥

首先我们需要使用 openssl 来创建服务器端的证书和私钥. 我使用的 openssl 版本为:

1
2
>>> /usr/local/Cellar/openssl/1.0.2j/bin/openssl version
OpenSSL 1.0.2j 26 Sep 2016

新建一个 ~/temp/cert 目录, 用于存放生成的证书和私钥

1
2
mkdir ~/temp/cert
cd ~/temp/cert

创建 CA 私钥和 CA 证书

然后, 我们先来生成一个 CA 私钥:

1
openssl genrsa 2048 > ca-key.pem

当有了一个 CA 私钥, 我们接下来就可以使用这个私钥生成一个新的数字证书:

1
openssl req -sha1 -new -x509 -nodes -days 3650 -key ca-key.pem > ca-cert.pem

执行这个命令时, 会需要填写一些问题, 随便填写就可以了. 例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> openssl req -sha1 -new -x509 -nodes -days 3650 -key ca-key.pem > ca-cert.pem

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Beijing
Locality Name (eg, city) []:Beijing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:xys
Organizational Unit Name (eg, section) []:xys
Common Name (e.g. server FQDN or YOUR name) []:xys
Email Address []:yongshun1228@gmail.com

执行上述命令后, 我们就有了一个 CA 私钥和一个 CA 证书.

创建服务器端的 RSA 私钥和数字证书

接着, 我们需要创建服务器端的私钥和一个证书请求文件, 命令如下:

1
openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem > server-req.pem

上面这个命令会生成一个新的私钥(server-key.pem), 同时会使用这个新私钥来生成一个证书请求文件(server-req.pem).
上面这个命令同样需要回答几个问题, 随便填写即可. 不过需要注意的是, A challenge password 这一项需要为空.
即:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
>>> openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem > server-req.pem

Generating a 2048 bit RSA private key
.................+++
..+++
writing new private key to 'server-key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Beijing
Locality Name (eg, city) []:Beijing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:xys
Organizational Unit Name (eg, section) []:xys
Common Name (e.g. server FQDN or YOUR name) []:xys
Email Address []:yongshun1228@gmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

下一步, 我们需要将生成的私钥转换为 RSA 私钥文件格式:

1
openssl rsa -in server-key.pem -out server-key.pem

最后一步, 我们需要使用原先生成的 CA 证书来生成一个服务器端的数字证书:

1
openssl x509 -sha1 -req -in server-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem

上面的命令会创建以服务器端的数字证书文件.

创建客户端的 RSA 私钥和数字证书

和服务器端所执行的命令类似, 我们也需要为客户端生成一个私钥和证书请求文件, 命令如下:

1
openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem > client-req.pem

同样地, 我们需要将生成的私钥转换为 RSA 私钥文件格式:

1
openssl rsa -in client-key.pem -out client-key.pem

最后, 我们也需要为客户端创建一个数字证书:

1
openssl x509 -sha1 -req -in client-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem

使用工具创建证书与私钥

前面我们介绍了如何使用 OpenSSL 来创建 SSL 连接的私钥和证书文件, 现在我们来看一个更简单的方法.
在 MySQL 5.7 中, 提供了一个名为 mysql_ssl_rsa_setup 的工具, 通过它, 我们可以很方便地创建 SSL 连接所需要的各种文件:

1
2
3
mkdir ~/temp/cert
cd ~/temp/cert
mysql_ssl_rsa_setup --datadir ./

上面的命令中, --datadir 表示生成的文件的目录.

当执行了上述命令后, 也会生成八个文件:

1
2
3
4
5
6
7
8
ca-key.pem
ca.pem
client-cert.pem
client-key.pem
private_key.pem
public_key.pem
server-cert.pem
server-key.pem

这些文件和我们使用 OpenSSL 所创建的那八个文件的作用是一样的, 这里就不再详述了.

SSL 配置

在前面的步骤中, 我们已经生成了8个文件, 分别是:

  • ca-cert.pem: CA 证书, 用于生成服务器端/客户端的数字证书.

  • ca-key.pem: CA 私钥, 用于生成服务器端/客户端的数字证书.

  • server-key.pem: 服务器端的 RSA 私钥

  • server-req.pem: 服务器端的证书请求文件, 用于生成服务器端的数字证书.

  • server-cert.pem: 服务器端的数字证书.

  • client-key.pem: 客户端的 RSA 私钥

  • client-req.pem: 客户端的证书请求文件, 用于生成客户端的数字证书.

  • client-cert.pem: 客户端的数字证书.

接下来我们就需要分别配置服务器端和客户端.

服务器端配置

服务器端需要用到三个文件, 分别是: CA 证书, 服务器端的 RSA 私钥, 服务器端的数字证书, 我们需要在 [mysqld] 配置域下添加如下内容:

1
2
3
4
[mysqld]
ssl-ca=/etc/mysql/ca-cert.pem
ssl-cert=/etc/mysql/server-cert.pem
ssl-key=/etc/mysql/server-key.pem

接着我们还可以更改 bind-address, 使 MySQL 服务可以接收来自所有 ip 地址的客户端, 即:

1
bind-address = *

当配置好后, 我们需要重启 MySQL 服务, 使能配置.

最后一步, 我们添加一个需要使用 SSL 才可以登录的帐号, 来验证一下我们所配置的 SSL 是否生效:

1
2
GRANT ALL PRIVILEGES ON *.* TO 'ssl_test'@'%' IDENTIFIED BY 'ssl_test' REQUIRE SSL;
FLUSH PRIVILEGES;

当配置好后, 使用 root 登录 MySQL, 执行 show variables like '%ssl%' 语句会有如下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> show variables like '%ssl%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| have_openssl | YES |
| have_ssl | YES |
| ssl_ca | ca.pem |
| ssl_capath | |
| ssl_cert | server-cert.pem |
| ssl_cipher | |
| ssl_crl | |
| ssl_crlpath | |
| ssl_key | server-key.pem |
+---------------+-----------------+
9 rows in set (0.01 sec)

客户端配置

客户端配置相对简单一些. 首先我们需要拷贝 ca-cert.pem, client-cert.pemclient-key.pem 这三个文件到客户端主机中, 然后我们可以执行如下命令来使用 SSL 连接 MySQL 服务:

1
mysql --ssl-ca=/path/to/ca-cert.pem --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem -h host_name -u ssl_test -p

除了上述的使用命令行方式配置 SSL 外, 我们也可以使用配置文件的方式. 即在 ~/.my.cnf 文件中添加如下内容即可:

1
2
3
4
[client]
ssl-ca=/path/to/ca-cert.pem
ssl-cert=/path/to/client-cert.pem
ssl-key=/path/to/client-key.pem

当连接成功后, 我们执行如下指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
mysql> \s
--------------
mysql Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using EditLine wrapper

Connection id: 14
Current database:
Current user: ssl_test@172.17.0.4
SSL: Cipher in use is DHE-RSA-AES256-SHA
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.7.17 MySQL Community Server (GPL)
Protocol version: 10
Connection: test_db via TCP/IP
Server characterset: latin1
Db characterset: latin1
Client characterset: latin1
Conn. characterset: latin1
TCP port: 3306
Uptime: 1 hour 2 min 9 sec

Threads: 1 Questions: 23 Slow queries: 0 Opens: 126 Flush tables: 3 Open tables: 0 Queries per second avg: 0.006
--------------

如果输出中有 SSL: Cipher in use is DHE-RSA-AES256-SHA 之类的信息, 则表示已经使用 SSL 来连接了.

在 Docker 中使能 MySQL SSL 连接

上面我们简单介绍了一下如果使能 MySQL SSL 连接, 那么现在我们使用 Docker 来具体的实战一把吧!

首先拉取最新的 MySQL 镜像:

1
docker pull mysql

然后需要准备一下挂载到 Docker 容器的目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> cd ~/temp
>>> tree
.
├── cert
│ ├── ca-key.pem
│ ├── ca.pem
│ ├── client-cert.pem
│ ├── client-key.pem
│ ├── private_key.pem
│ ├── public_key.pem
│ ├── server-cert.pem
│ └── server-key.pem
├── config
│ └── my.cnf
└── db

3 directories, 9 files

在 temp 目录下有三个子目录:

  • cert 目录用于存放我们先前生成的证书和私钥信息;

  • config 目录用于存放 MySQL 服务的配置文件

  • db 目录是用于存放 MySQL 的数据.

下一步我们需要使用如下命令启动 MySQL 容器:

1
docker run --rm --name test_db -p 10000:3306 -e MYSQL_ROOT_PASSWORD=root -v /Users/xiongyongshun/temp/db:/var/lib/mysql -v /Users/xiongyongshun/temp/config:/etc/mysql/conf.d -v /Users/xiongyongshun/temp/cert:/etc/mysql/cert mysql:latest

我们在上面的命令中, 我们分别挂载了 cert, config, db 这三个宿主机上的目录到 MySQL 容器中.

启动了 MySQL 服务后, 可以先使用 root 帐号登录 MySQL, 来检查 MySQL 服务此时是否已经开启了 SSL 功能:

1
docker run -it --link test_db:test_db --rm  mysql sh -c 'exec mysql -u root -p -h test_db'

登录成功后, 我们在 MySQL 中执行如下指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> show variables like '%ssl%';
+---------------+---------------------------------+
| Variable_name | Value |
+---------------+---------------------------------+
| have_openssl | YES |
| have_ssl | YES |
| ssl_ca | /etc/mysql/cert/ca-cert.pem |
| ssl_capath | |
| ssl_cert | /etc/mysql/cert/server-cert.pem |
| ssl_cipher | |
| ssl_crl | |
| ssl_crlpath | |
| ssl_key | /etc/mysql/cert/server-key.pem |
+---------------+---------------------------------+
9 rows in set (0.01 sec)

有上面的输出后, 表明此时 MySQL 服务已经使用 SSL 功能了.

接着下一步, 我们按照前面所提到的, 创建一个仅仅可以使用 SSL 登录的帐号, 来检验我们的配置是否有效:

1
2
GRANT ALL PRIVILEGES ON *.* TO 'ssl_test'@'%' IDENTIFIED BY 'ssl_test' REQUIRE SSL;
FLUSH PRIVILEGES;

上面的命令创建了一个帐号名为 ssl_test, 密码为 ssl_test, 并且不限制登录主机 ip 的帐号.

这些都配置成功后, 我们再启动一个 MySQL 客户端容器:

1
docker run -it --link test_db:test_db --rm -v /Users/xiongyongshun/temp/cert:/etc/mysql/cert mysql sh -c 'exec mysql --ssl-ca=/etc/mysql/cert/ca-cert.pem --ssl-cert=/etc/mysql/cert/client-cert.pem --ssl-key=/etc/mysql/cert/client-key.pem -h test_db -u ssl_test -p'

从上面的这个命令中我们可以看到, 启动 MySQL 客户端容器时, 我们挂载了宿主机的 cert 目录到容器内的 /etc/mysql/cert 目录, 这样在容器中就可以访问到 SSL 私钥和证书文件了. 接着我们在 MySQL 客户端命令行中, 使用 --ssl-ca, --ssl-cert, --ssl-key 这三个参数来指定 SSL 连接所需要的 CA 证书, RSA 私钥和客户端证书.

登录成功后, 我们执行 s 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
mysql> \s
--------------
mysql Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using EditLine wrapper

Connection id: 5
Current database:
Current user: ssl_test@172.17.0.5
SSL: Cipher in use is DHE-RSA-AES256-SHA
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.7.17 MySQL Community Server (GPL)
Protocol version: 10
Connection: test_db via TCP/IP
Server characterset: latin1
Db characterset: latin1
Client characterset: latin1
Conn. characterset: latin1
TCP port: 3306
Uptime: 6 min 8 sec

Threads: 2 Questions: 10 Slow queries: 0 Opens: 113 Flush tables: 1 Open tables: 106 Queries per second avg: 0.027
--------------

输出中有 SSL: Cipher in use is DHE-RSA-AES256-SHA 信息则说明我们确实是使用了 SSL 连接的 MySQL 服务器.

留言與分享

CentOs7.3 安装 MySQL 5.7.19 二进制版本

参考官网 - 使用通用二进制文件在Unix / Linux上安装MySQL

MySQL社区版 下载地址

采用二进制方式免编译安装MySQL,适合各类MySQL产品系列,不需要复杂的编译设置和编译时间等待,直接解压下载的软件包,初始化即可完成MySQL的安装和启动.

1.准备工作

依赖环境

关闭防火墙

1
$ systemctl stop firewalld.service

MySQL依赖于libaio 库

1
2
$ yum search libaio
$ yum install libaio

下载,解压,重命名

通常解压在 /usr/local/mysql

mysql-5.7.19-linux-glibc2.12-x86_64 文件夹,重命名成mysql,这样就凑成/usr/local/mysql目录了

1
2
3
4
$ cd /opt/
$ wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-linux-glibc2.12-x86_64.tar.gz
$ tar -zxvf /opt/mysql-5.7.19-linux-glibc2.12-x86_64.tar.gz -C /usr/local/
$ mv /usr/local/mysql-5.7.19-linux-glibc2.12-x86_64/ /usr/local/mysql

解压目录内容

bin mysqld服务器,客户端和实用程序
data 日志文件,数据库
docs MySQL手册信息格式
man Unix手册页
include 包含(标题)文件
lib
share 其他支持文件,包括错误消息,示例配置文件,用于数据库安装的SQL

2.安装MySQL

1. 新建用户组和用户

1
2
3
$ cd /usr/local/mysql/ 
$ groupadd mysql
$ useradd mysql -g mysql

2. 创建目录并授权

1
2
3
4
$ mkdir data mysql-files
$ chmod 750 mysql-files
$ chown -R mysql .
$ chgrp -R mysql .

3. 初始化MySQL

1
$ bin/mysqld --initialize --user=mysql # MySQL 5.7.6 and up

注意密码

4. mysql 临时密码

[注意]root@localhost生成临时密码:;b;s;)/rn6A3,也就是root@localhost:后的字符串

1
2
3
4
5
6
2017-08-26T03:23:35.368366Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2017-08-26T03:23:35.748679Z 0 [Warning] InnoDB: New log files created, LSN=45790
2017-08-26T03:23:35.793190Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
2017-08-26T03:23:35.848286Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: f210c54b-8a0d-11e7-abbd-000c29129bb0.
2017-08-26T03:23:35.848889Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
2017-08-26T03:23:35.849421Z 1 [Note] A temporary password is generated for root@localhost: ;b;s;)/rn6A3

5. 生成RSA私钥,可以跳过此步骤

mysql_ssl_rsa_setup需要openssl支持,用于启用数据量ssl连接,需要进一步配置。

参考-MySQL 使用 SSL 连接

1
$ bin/mysql_ssl_rsa_setup 

6. 授予读写权限

1
2
$ chown -R root .
$ chown -R mysql data mysql-files

7. 添加到MySQL 启动脚本到系统服务

1
$ cp support-files/mysql.server /etc/init.d/mysql.server

3.启动MySQL服务

启动脚本有两个分别是:

/usr/local/mysql/bin/mysqld_safe
/usr/local/mysql/support-files/mysql.server(即/etc/init.d/mysqld

当启动mysqld时,mysqld_safe同时启动

mysqld_safe监控mysqld服务,记录错误日志,并在mysqld因故障停止时将其重启

启动方式一

1
$ bin/mysqld_safe --user=mysql &

启动方式二

1
$ service mysql.server start

或者

1
/usr/local/mysql/support-files/mysql.server start

如若出现报错

1
2
Starting MySQL.2017-08-26T07:31:24.312411Z mysqld_safe error: log-error set to '/var/log/mariadb/mariadb.log', however file don't exists. Create writable for user 'mysql'.
ERROR! The server quit without updating PID file (/var/lib/mysql/node1.pid).

给日志目录授予读写权限

1
2
3
$ mkdir /var/log/mariadb
$ touch /var/log/mariadb/mariadb.log
$ chown -R mysql:mysql /var/log/mariadb

4.登录MySQL

1
2
$ /usr/local/mysql/bin/mysql -uroot -p
Enter password:

如果不知道密码
密码在,安装MySQL步骤 4 ,有提到,怎么找初始化临时密码

如若出现报错

1
2
Enter password: 
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

故障分析

查看mysql实例的状态

1
2
$ netstat -ntlp  | grep 3306
tcp6 0 0 :::3306 :::* LISTEN 10794/mysqld

查看my.cnf关于socket的配置

1
2
$ more /etc/my.cnf |grep sock
socket=/var/lib/mysql/mysql.sock

解决方法,修改/etc/my.cnf

1
$ vi /etc/my.cnf

修改 [mysqld]组下的 socket 路径,我是选择注释掉,加一行为tmp/mysql.soc

1
2
3
4
[mysqld]
datadir=/var/lib/mysql
#socket=/var/lib/mysql/mysql.sock
socket=/tmp/mysql.sock

重启MySQL 服务

1
2
$ service mysql.server start
Shutting down MySQL.. SUCCESS!

再次登录

1
$ /usr/local/mysql/bin/mysql -uroot -p

如果不知道密码
密码在,安装MySQL步骤 4 ,有提到,怎么找初始化临时密码

设置MySQL密码

登陆成功后,设置MySQL密码

1
mysql> ALTER USER   'root'@'localhost' identified by 'mima';  

或者

1
mysql> set password=password("mima");

刷新权限

1
2
mysql> flush privileges;
mysql> exit;

查看mysql.user表中存在哪些帐户 以及它们的密码是否为空:

MySQL 5.7.6起,使用这个语句:

1
2
3
4
5
6
7
8
mysql> SELECT User, Host, HEX(authentication_string) FROM mysql.user;
+---------------+-----------+------------------------------------------------------------------------------------+
| User | Host | HEX(authentication_string) |
+---------------+-----------+------------------------------------------------------------------------------------+
| root | localhost | 2A39383730334637413534333934344644333831383037373636394637344436303631364442324338 |
| mysql.session | localhost | 2A5448495349534E4F544156414C494450415353574F52445448415443414E42455553454448455245 |
| mysql.sys | localhost | 2A5448495349534E4F544156414C494450415353574F52445448415443414E42455553454448455245 |
+---------------+-----------+------------------------------------------------------------------------------------+

开启远程登录

关闭防火墙

1
$ systemctl stop firewalld.service

以权限用户root登录

1
$ /usr/local/mysql/bin/mysql -uroot -p
1
2
3
mysql> use mysql;
mysql> update user set host = '%' where user ='root';
mysql> flush privileges;

第1行:选择mysql库
第2行:修改host值(以通配符%的内容增加主机/IP地址),当然也可以直接增加IP地址
第3行:刷新MySQL的系统权限相关表

或者

1
2
mysql> grant all privileges on *.*  to  'root'@'%'  identified by 'mima'  with grant option;
mysql> flush privileges;

推荐阅读

CentOs7.3 搭建 MySQL 5.7.19 主从复制,以及复制实现细节分析

留言與分享

git教程

分類 devops, git
初始化仓库:
1
git init

如果当前目录下有几个文件想要纳入版本控制,需要先用 git add 命令告诉 Git 开始对这些文件进行跟踪,然后提交:

1
2
3
$ git add *.c
$ git add README
$ git commit -m 'initial project version'

image

忽略某些文件

我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式。
文件 .gitignore 的格式规范如下:

  • 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。
  • 可以使用标准的 glob 模式匹配。
  • 匹配模式最后跟反斜杠(/)说明要忽略的是目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。

所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。

我们再看一个 .gitignore 文件的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 此为注释 – 将被 Git 忽略
# 忽略所有 .a 结尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目录下的所有文件
build/
# 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录下所有扩展名为 txt 的文件
doc/**/*.txt
跟踪新文件

使用命令 git add 开始跟踪一个新文件。所以,要跟踪 README 文件,运行:

1
$ git add README
提交更新

每次准备提交前,先用 git status 看下,是不是都已暂存起来了,然后再运行提交命令 git commit:

1
$ git commit

这种方式会启动文本编辑器以便输入本次提交的说明。(默认会启用 shell 的环境变量 $EDITOR 所指定的软件,一般都是 vim 或 emacs。当然也可以按照第一章介绍的方式,使用 ++git config --global core.editor++ 命令设定你喜欢的编辑软件。)

默认的提交消息包含最后一次运行 git status 的输出,放在注释行里,另外开头还有一空行,供你输入提交说明。你完全可以去掉这些注释行,不过留着也没关系,多少能帮你回想起这次更新的内容有哪些。(如果觉得这还不够,可以用 -v 选项将修改差异的每一行都包含到注释中来。)退出编辑器时,Git 会丢掉注释行,将说明内容和本次更新提交到仓库。

另外也可以用 +±m++ 参数后跟提交说明的方式,在一行命令中提交更新:

跳过使用暂存区域
Git 提供了一个跳过使用暂存区域的方式,只要在提交的时候,给 git commit 加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤

移除文件

要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。可以用 git rm 命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。

移动文件

要在 Git 中对文件改名,可以这么做:

1
$ git mv file_from file_to

运行 git mv 就相当于运行了下面三条命令:

1
2
3
$ mv README.txt README
$ git rm README.txt
$ git add README
查看提交历史

默认不用任何参数的话,git log 会按提交时间列出所有的更新,最近的更新排在最上面。看到了吗,每次更新都有一个 SHA-1 校验和、作者的名字和电子邮件地址、提交时间,最后缩进一个段落显示提交说明。

git log 有许多选项可以帮助你搜寻感兴趣的提交,接下来我们介绍些最常用的。

我们常用 -p 选项展开显示每次提交的内容差异,用 -2 则仅显示最近的两次更新

某些时候,单词层面的对比,比行层面的对比,更加容易观察。Git 提供了 +±-word-diff++ 选项。我们可以将其添加到 ++git log -p++ 命令的后面,从而获取单词层面上的对比。在程序代码中进行单词层面的对比常常是没什么用的。不过当你需要在书籍、论文这种很大的文本文件上进行对比的时候,这个功能就显出用武之地了。

另外,git log 还提供了许多摘要选项可以用,比如 --stat,仅显示简要的增改行数统计

用 oneline 或 format 时结合 --graph 选项,可以看到开头多出一些 ASCII 字符串表示的简单图形,形象地展示了每个提交所在的分支及其分化衍合情况。

另外还有按照时间作限制的选项,比如 --since 和 --until。

撤消操作

有时候我们提交完了才发现漏掉了几个文件没有加,或者提交信息写错了。想要撤消刚才的提交操作,可以使用 --amend 选项重新提交:

1
$ git commit --amend

撤消操作

远程仓库的使用

查看当前的远程库
要查看当前配置有哪些远程仓库,可以用 git remote 命令,它会列出每个远程库的简短名字。
也可以加上 -v 选项(译注:此为 --verbose 的简写,取首字母),显示对应的克隆地址

添加远程仓库

要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用,运行

1
git remote add [shortname] [url]:

现在可以用字符串 pb 指代对应的仓库地址了。比如说,要抓取所有 Paul 有的,但本地仓库没有的信息,可以运行 git fetch pb

从远程仓库抓取数据

正如之前所看到的,可以用下面的命令从远程仓库抓取数据到本地:

1
$ git fetch [remote-name]

推送数据到远程仓库

目进行到一个阶段,要同别人分享目前的成果,可以将本地仓库中的数据推送到远程仓库。实现这个任务的命令很简单:

1
git push [remote-name] [branch-name]。

如果要把本地的 master 分支推送到 origin 服务器上(再次说明下,克隆操作会自动使用默认的 master 和 origin 名字),可以运行下面的命令:

1
$ git push origin master

查看远程仓库信息
我们可以通过命令

1
git remote show [remote-name]

查看某个远程仓库的详细信息

远程仓库的删除和重命名
在新版 Git 中可以用 git remote rename 命令修改某个远程仓库在本地的简称,比如想把 pb 改成 paul,可以这么运行:

1
2
3
4
$ git remote rename pb paul
$ git remote
origin
paul

碰到远端仓库服务器迁移,或者原来的克隆镜像不再使用,又或者某个参与者不再贡献代码,那么需要移除对应的远端仓库,可以运行 git remote rm 命令:

1
2
3
$ git remote rm paul
$ git remote
origin
打标签

打标签

Git 命令别名

Git 并不会推断你输入的几个字符将会是哪条命令,不过如果想偷懒,少敲几个命令的字符,可以用 git config 为命令设置别名。来看看下面的例子:

1
2
3
4
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status

取消暂存文件时的输入比较繁琐,可以自己设置一下:

1
$ git config --global alias.unstage 'reset HEAD --'

这样一来,下面的两条命令完全等同:

1
2
$ git unstage fileA
$ git reset HEAD fileA

显然,使用别名的方式看起来更清楚。另外,我们还经常设置 last 命令:

1
$ git config --global alias.last 'log -1 HEAD'

然后要看最后一次的提交信息,就变得简单多了

分支的新建与切换

要新建并切换到该分支,运行 git checkout 并加上 -b 参数:

1
2
$ git checkout -b iss53
Switched to a new branch 'iss53'

回到 master 分支并把它合并进来,然后发布到生产服务器。用 git merge 命令来进行合并:

1
2
3
4
5
6
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
README | 1 -
1 file changed, 1 deletion(-)

这相当于执行下面这两条命令:

1
2
$ git branch iss53
$ git checkout iss53

如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,因为这种单线的历史分支不存在任何需要解决的分歧,所以这种合并过程可以称为快进(Fast forward)。

合并之后,master 分支和 hotfix 分支指向同一位置。
由于当前 hotfix 分支和 master 都指向相同的提交对象,所以 hotfix 已经完成了历史使命,可以删掉了。使用 git branch 的 -d 选项执行删除操作:

1
2
$ git branch -d hotfix
Deleted branch hotfix (was 3a0874c).
遇到冲突时的分支合并

有时候合并操作并不会如此顺利。如果在不同的分支中都修改了同一个文件的同一部分,Git 就无法干净地把两者合到一起(译注:逻辑上说,这种问题只能由人来裁决。)。
Git 作了合并,但没有提交,它会停下来等你解决冲突。要看看哪些文件在合并时发生冲突,可以用 git status 查阅

任何包含未解决冲突的文件都会以未合并(unmerged)的状态列出。Git 会在有冲突的文件里加入标准的冲突解决标记,可以通过它们来手工定位并解决这些冲突。可以看到此文件包含类似下面这样的部分:

1
2
3
4
5
6
7
<<<<<<< HEAD
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53

可以看到 ======= 隔开的上半部分,是 HEAD(即 master 分支,在运行 merge 命令时所切换到的分支)中的内容,下半部分是在 iss53 分支中的内容。解决冲突的办法无非是二者选其一或者由你亲自整合到一起。比如你可以通过把这段内容替换为下面这样来解决:

1
2
3
<div id="footer">
please contact us at email.support@github.com
</div>

这个解决方案各采纳了两个分支中的一部分内容,而且我还删除了 <<<<<<<,======= 和 >>>>>>> 这些行。在解决了所有文件里的所有冲突后,运行 git add 将把它们标记为已解决状态(译注:实际上就是来一次快照保存到暂存区域。)。

再运行一次 git status 来确认所有冲突都已解决:

1
2
3
4
5
6
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

modified: index.html

如果觉得满意了,并且确认所有冲突都已解决,也就是进入了暂存区,就可以用 git commit 来完成这次合并提交。提交的记录差不多是这样:

1
2
3
4
5
6
7
8
9
10
Merge branch 'iss53'

Conflicts:
index.html
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
#
查看当前的远程库

要查看当前配置有哪些远程仓库,可以用 git remote 命令,它会列出每个远程库的简短名字。
可以加上 -v 选项(译注:此为 --verbose 的简写,取首字母),显示对应的克隆地址

添加远程仓库

要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用,运行

1
git remote add [shortname] [url]:
从远程仓库抓取数据

正如之前所看到的,可以用下面的命令从远程仓库抓取数据到本地:

1
$ git fetch [remote-name]

推送数据到远程仓库
项目进行到一个阶段,要同别人分享目前的成果,可以将本地仓库中的数据推送到远程仓库。实现这个任务的命令很简单: git push [remote-name] [branch-name]。如果要把本地的 master 分支推送到 origin 服务器上(再次说明下,克隆操作会自动使用默认的 master 和 origin 名字),可以运行下面的命令:

1
$ git push origin master

只有在所克隆的服务器上有写权限,或者同一时刻没有其他人在推数据,这条命令才会如期完成任务。如果在你推数据前,已经有其他人推送了若干更新,那你的推送操作就会被驳回。你必须先把他们的更新抓取到本地,合并到自己的项目中,然后才可以再次推送。

查看远程仓库信息
我们可以通过命令

1
git remote show [remote-name]

查看某个远程仓库的详细信息

远程仓库的删除和重命名
在新版 Git 中可以用 git remote rename 命令修改某个远程仓库在本地的简称,比如想把 pb 改成 paul,可以这么运行:

1
2
3
4
$ git remote rename pb paul
$ git remote
origin
paul

注意,对远程仓库的重命名,也会使对应的分支名称发生变化,原来的 pb/master 分支现在成了 paul/master。

碰到远端仓库服务器迁移,或者原来的克隆镜像不再使用,又或者某个参与者不再贡献代码,那么需要移除对应的远端仓库,可以运行 git remote rm 命令:

1
2
3
$ git remote rm paul
$ git remote
origin
远程分支

我们用 ==(远程仓库名)/(分支名)== 这样的形式表示远程分支。比如我们想看看上次同 origin 仓库通讯时 master 分支的样子,就应该查看 origin/master 分支。如果你和同伴一起修复某个问题,但他们先推送了一个 iss53 分支到远程仓库,虽然你可能也有一个本地的 iss53 分支,但指向服务器上最新更新的却应该是 origin/iss53 分支。

可以运行 git fetch origin 来同步远程服务器上的数据到本地。该命令首先找到 origin 是哪个服务器(本例为 git.ourcompany.com),从上面获取你尚未拥有的数据,更新你本地的数据库,然后把 origin/master 的指针移到它最新的位置上
image

为了演示拥有多个远程分支(在不同的远程服务器上)的项目是如何工作的,我们假设你还有另一个仅供你的敏捷开发小组使用的内部服务器 git.team1.ourcompany.com。可以用第二章中提到的 git remote add 命令把它加为当前项目的远程分支之一。我们把它命名为 teamone,以便代替完整的 Git URL 以方便使用
image
现在你可以用 git fetch teamone 来获取小组服务器上你还没有的数据了。由于当前该服务器上的内容是你 origin 服务器上的子集,Git 不会下载任何数据,而只是简单地创建一个名为 teamone/master 的远程分支,指向 teamone 服务器上 master 分支所在的提交对象 31b8e(见图 3-26)。

image

推送本地分支

要想和其他人分享某个本地分支,你需要把它推送到一个你拥有写权限的远程仓库。你创建的本地分支不会因为你的写入操作而被自动同步到你引入的远程服务器上,你需要明确地执行推送分支的操作。

如果你有个叫 serverfix 的分支需要和他人一起开发,可以运行 git push (远程仓库名) (分支名):

1
2
3
4
5
6
7
$ git push origin serverfix
Counting objects: 20, done.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (15/15), 1.74 KiB, done.
Total 15 (delta 5), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
* [new branch] serverfix -> serverfix

这里其实走了一点捷径。Git 自动把 serverfix 分支名扩展为 refs/heads/serverfix:refs/heads/serverfix,意为“取出我在本地的 serverfix 分支,推送到远程仓库的 serverfix 分支中去”。

也可以运行 ==git push origin serverfix:serverfix== 来实现相同的效果,它的意思是“上传我本地的 serverfix 分支到远程仓库中去,仍旧称它为 serverfix 分支”。通过此语法,你可以把本地分支推送到某个命名不同的远程分支:若想把远程分支叫作 awesomebranch,可以用 git push origin serverfix:awesomebranch 来推送数据。

跟踪远程分支

从远程分支 checkout 出来的本地分支,称为 跟踪分支 (tracking branch)。跟踪分支是一种和某个远程分支有直接联系的本地分支。在跟踪分支里输入 git push,Git 会自行推断应该向哪个服务器的哪个分支推送数据。同样,在这些分支里运行 git pull 会获取所有远程索引,并把它们的数据都合并到本地分支中来。

在克隆仓库时,Git 通常会自动创建一个名为 master 的分支来跟踪 origin/master。这正是 git push 和 git pull 一开始就能正常工作的原因。当然,你可以随心所欲地设定为其它跟踪分支,比如 origin 上除了 master 之外的其它分支。刚才我们已经看到了这样的一个例子:git checkout -b [分支名] [远程名]/[分支名]。如果你有 1.6.2 以上版本的 Git,还可以用 --track 选项简化:

1
2
3
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

要为本地分支设定不同于远程分支的名字,只需在第一个版本的命令里换个名字:

1
2
3
$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'

现在你的本地分支 sf 会自动将推送和抓取数据的位置定位到 origin/serverfix 了

删除远程分支

如果不再需要某个远程分支了,比如搞定了某个特性并把它合并进了远程的 master 分支(或任何其他存放稳定代码的分支),可以用这个非常无厘头的语法来删除它:git push [远程名] :[分支名]。如果想在服务器上删除 serverfix 分支,运行下面的命令:

1
2
3
$ git push origin :serverfix
To git@github.com:schacon/simplegit.git
- [deleted] serverfix

咚!服务器上的分支没了。你最好特别留心这一页,因为你一定会用到那个命令,而且你很可能会忘掉它的语法。有种方便记忆这条命令的方法:==记住我们不久前见过的 git push [远程名] [本地分支]:[远程分支] 语法,如果省略 [本地分支],那就等于是在说“在这里提取空白然后把它变成[远程分支]”==。

解决远程分支和本地冲突

1.先将本地修改储存起来

1
git stash

2.pull内容

1
git pull

3.还原暂存内容

1
git stash pop stash@{0}

4.解决冲突

5.提交

1
git commit -m ''
  1. 打标签
1
git tag v1.1 -m ''

7.列标签

1
git tag -l

8.获取标签代码

1
git checkout 

9.提交标签到远程端

1
git push tag 
拉取本地没有的远程分支
1
git checkout -b 本地分支名 origin/远程分支名

后续:变基rebase

留言與分享

Scala-2.13.0 安装及配置

分類 编程语言, scala

Scala 简介

Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。

Scala 运行在Java虚拟机上,并兼容现有的Java程序。

Scala 源代码被编译成Java字节码,所以它可以运行于JVM之上,并可以调用现有的Java类库。

准备工作

环境

1
2
JDK:1.8  
Scala:Scala-2.13.0

依赖环境

Scala 语言可以运行在Window、Linux、Unix、 Mac OS X等系统上。

Scala是基于java之上,大量使用java的类库和变量,必须使用Scala之前必须先安装 Java

安装 JDK

CentOs7.3 安装 JDK1.8

安装

确保你本地以及安装了 JDK 1.8 以上版本,并且设置了 JAVA_HOME 环境变量及 JDK 的bin目录。

下载解压

解压缩文件包,可将其移动至/lib/下:

1
2
3
4
5
su hadoop
cd /home/hadoop/
wget https://downloads.lightbend.com/scala/2.13.0-M2/scala-2.13.0-M2.tgz
sudo tar -zxvf scala-2.13.0-M2.tgz -C /lib/
sudo mv /lib/scala-2.13.0-M2/ /lib/scala

环境变量

如果是对所有的用户都生效就修改vi /etc/profile 文件
如果只针对当前用户生效就修改 vi ~/.bahsrc 文件

1
sudo vi /etc/profile
1
2
3
#scala
export SCALA_HOME=/lib/scala
export PATH=${SCALA_HOME}/bin:$PATH

使环境变量生效,运行 source /etc/profile使/etc/profile文件生效

验证

:wq!保存退出,重启终端,执行 scala 命令,输出以下信息,表示安装成功:

1
scala
1
2
3
4
5
6
Welcome to Scala 2.13.0-M2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.

scala> scala> println("Hello World!")
Hello World!
scala>

留言與分享

Hadoop简介

2003-2004年,Google公开了部分GFS和Mapreduce思想的细节,以此为基础Doug Cutting等人用了2年业余时间实现了DFS和Mapreduce机制,一个微缩版:Nutch

Hadoop 于 2005 年秋天作为 Lucene的子项目 Nutch的一部分正式引入Apache基金会。2006 年 3 月份,Map-Reduce 和 Nutch Distributed File System (NDFS) 分别被纳入称为 Hadoop 的项目中

Hadoop

分布式存储系统HDFS (Hadoop Distributed File System )

  • 分布式存储系统
  • 提供了 高可靠性、高扩展性和高吞吐率的数据存储服务

分布式计算框架MapReduce

  • 分布式计算框架
  • 具有 易于编程、高容错性和高扩展性等优点。

HDFS优点

高容错性

  • 数据自动保存多个副本
  • 副本丢失后,自动恢复

适合批处理

  • 移动计算而非数据
  • 数据位置暴露给计算框架

适合大数据处理

  • GB 、TB 、甚至PB 级数据
  • 百万规模以上的文件数量
  • 10K+ 节点

可构建在廉价机器上

  • 通过多副本提高可靠性
  • 提供了容错和恢复 机制

HDFS缺点

低延迟数据访问

  • 比如毫秒级
  • 低延迟与高吞吐率

小文件存取

  • 占用NameNode 大量内存
  • 寻道时间超过读取时间

并发写入、文件随机修改

  • 一个文件只能有一个写者
  • 仅支持append

准备工作

环境

1
2
3
4
5
6
7
JDK:1.8  
Hadoop Release:2.7.4
centos:7.3

node1(master) 主机: 192.168.252.121
node2(slave1) 从机: 192.168.252.122
node3(slave2) 从机: 192.168.252.123

安装 JDK

CentOs7.3 安装 JDK1.8

SSH 免秘钥

CentOs7.3 Hadoop 用户 ssh 免密登录

创建用户

建议创建一个单独的用户Hadoop以从Unix文件系统隔离Hadoop文件系统

1
2
3
4
$ useradd hadoop
$ passwd hadoop
New password:
Retype new password:

授权 root 权限,在root下面加一条hadoophadoop ALL=(ALL) ALL

1
2
3
4
5
$ chmod 777 /etc/sudoers
$ vi /etc/sudoers
root ALL=(ALL) ALL
hadoop ALL=(ALL) NOPASSWD:ALL
$ pkexec chmod 0440 /etc/sudoers

免秘钥登录

安装

下载解压

在 ndoe1 上操作

1
2
3
4
su hadoop
cd /home/hadoop/
wget https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-2.7.4/hadoop-2.7.4.tar.gz
tar -zxvf hadoop-2.7.4.tar.gz

环境变量

如果是对所有的用户都生效就修改vi /etc/profile 文件
如果只针对当前用户生效就修改 vi ~/.bahsrc 文件

1
sudo vi /etc/profile
1
2
3
#hadoop
export PATH=${HADOOP_HOME}/bin:$PATH
export HADOOP_HOME=/home/hadoop/hadoop-2.7.4/

使环境变量生效,运行 source /etc/profile使/etc/profile文件生效

配置Hadoop

进入hadoop 配置文件目录

1
cd /home/hadoop/hadoop-2.7.4/etc/hadoop/

编辑 hadoop-env.sh 文件,找到 JAVA_HOME 改为 JDK 的安装目录

1
sudo vi hadoop-env.sh
1
export JAVA_HOME=/lib/jvm

修改 core-site.xml

打开 core-site.xml文件并对其进行编辑,如下图所示。

1
vi core-site.xml
1
2
3
4
5
6
7
8
9
10
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://node1:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>file:/home/hadoop/hadoop-2.7.4/tmp</value>
</property>
</configuration>

修改 hdfs-site.xml

打开hdfs-site.xml文件并对其进行编辑,如下图所示。

1
vi hdfs-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<configuration>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>node1:50090</value>
</property>
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/home/hadoop/hadoop-2.7.4/tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/home/hadoop/hadoop-2.7.4/tmp/dfs/data</value>
</property>
</configuration>

修改 mapred-site.xml

目录下么没有这个文件,这有一个模板,我们需要先拷贝一份

1
2
cp mapred-site.xml.template mapred-site.xml
vi mapred-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>node1:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>node1:19888</value>
</property>
</configuration>

修改 yarn-site.xml

1
vi yarn-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
<configuration>

<!-- Site specific YARN configuration properties -->

<property>
<name>yarn.resourcemanager.hostname</name>
<value>node1</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>

配置集群

复制节点

将 hadoop-2.7.4 文件夹重打包后复制到其他子节点

1
2
3
4
5
cd /home/hadoop/

tar zcvf hadoop.tar.gz hadoop-2.7.4
scp hadoop.tar.gz hadoop@node2:/home/hadoop/
scp hadoop.tar.gz hadoop@node3:/home/hadoop/

在其他子节点 解压

1
tar -zxvf hadoop.tar.gz

配置slaves文件

修改(Master主机)node1/etc/hadoop/slaves该文件指定哪些服务器节点是datanode节点。删除locahost,添加所有datanode节点的主机名

1
2
3
4
5
cd /home/hadoop/hadoop-2.7.4/etc/hadoop/

[hadoop@node1 hadoop]$ cat slaves
node2
node3

集群操作

Format

格式化namenode和datanode并启动,(在master上执行就可以了 不需要在slave上执行)

1
2
3
4
cd /home/hadoop/hadoop-2.7.4/bin

./hadoop namenode -format
./hadoop datanode -format

启动 hadoop

关闭防火墙

1
systemctl stop firewalld.service
1
2
3
4
5
6
cd /home/hadoop/hadoop-2.7.4/sbin


./start-dfs.sh
./start-yarn.sh
./mr-jobhistory-daemon.sh start historyserver

或者

1
2
3
./start-all.sh

./mr-jobhistory-daemon.sh start historyserver

查看进程服务

查看启动进程,缺少以下任一进程都表示出错

1
2
3
4
5
$ jps
2528 NameNode
2720 SecondaryNameNode
2872 ResourceManager
3151 JobHistoryServer

查看端口占用情况

1
netstat -tnlp | grep java

访问node1

1
2
3
http://192.168.252.121:50070

http://192.168.252.121:8088

图片描述

图片描述

图片描述

停止 hadoop

1
cd /home/hadoop/hadoop-2.7.4/sbin
1
./stop-all.sh

或者 jps 查看进程kill

留言與分享

iptables

分類 服务端, linux

基本操作


查看iptable版本

1
rpm -q iptables

查看iptables 规则

1
2
3
service iptables status
# 或
service -L --line-numbers

iptables的4个表分别是:

  • filter(过滤):数据包过滤/拦截,可以包含INPUT、FORWARD、OUTPUT这3个内置chain。
  • nat(地址转换):IP地址或端口号转换,可以包含PREROUTING、OUTPUT、POSTROUTING 3个内置chain,nat table在会话建立时会记录转换的对应关系,同一会话的回包和后续报文会自动地址转换,这是因为nat使用了ip_conntrack模块。
  • mangle(包管理):用来修改IP报文,可以包含PREROUTING、OUTPUT、INPUT、FORWARD、POSTROUTING 5个内置chain。
  • raw:此表的优先级高于ip_conntrack模块和其它的table,主要用于将有会话状态的连接(比如tcp)的数据包排除在会话外。可以包含POSTROUTING、OUTPUT两个内置chain。

看到这里肯定会有这样的疑问,为什么table只能包含一些而不是全部的chain呢?我想这个构架是按需设计而不是按功能设计的,尽管table不是包含所有的chain,但是每种功能的table都包含了实现这种功能所需的chain,即使包含更多的chain也是累赘或者无用的,而且实际上用起来也的确如此,够用了。

还有就是不同table生效优先顺序问题,先后优先级是这样的:

raw > mangle > nat > filter

所以,如果有filter禁止ping目的地址2.2.2.2,而nat又有策略将目的地址1.1.1.1转换成2.2.2.2,那么ping 1.1.1.1是ping不通的。

不过一般情况下filter是不会和nat的策略打起架来,比如INPUT chain能做filter,却不能做nat,PREROUTING能做nat却不能做filter,而且PREROUTING只能做目的地址转换,不会对源地址过滤的需求造成麻烦,所以通常是不会相互干扰的。

规则链(chain)

iptables内置的5个chain:PREROUTING、INPUT、OUPUT、FORWARD、POSTROUGING,这5个chain分别与netfilter中数据转发路径上的5个不同的位置挂钩,以匹配筛选不同类型的数据流,如下图所示:

其中:

  • PREROUTING链:应用于所有进入机器的ip包,包括目的地址是本机和目的地址非本机的包。
  • INPUT链:应用于所有目的是本机的包,也就是目的IP是本机接口地址,所有发给本地socket的数据都经过它。
  • OUPUT链:应用于所有由本机产生的包,所有应用程序发出的数据都经过它。
  • FORWARD链:应用于所有经过路由决策被转发的包,也就是目的地址不是本机的数据包。
  • POSTROUGING链:应用于所有发出机器的IP包,包括本机发出的和从本机转发的数据包。

策略匹配按照重上到下的顺序进行,当测试到某策略匹配时执行target并跳出,不再向下匹配,当测试到最后一条策略仍不匹配时,则采用policy指定的动作,如下图:

除了内置chain外,还可以自定义chain,自定义chain并不能利用netfilter的hook来捕捉数据包,但是可用于策略的分类,比如有3类不同的用户访问主机上的不同服务,如果所有策略都放在INPUT chain中策略会多而难以维护,这个时候就可以定义3个自定义chain,分别配置不同的策略,同时在INPUT chain中添加策略对来访者分类并将目标指向3个自定义chain。

自定义chain大显神威的地方在于动态生成策略,例如VPN服务器上,需要对不同分组的用户区别对待管理,但是用户IP是随机分配的,不能根据IP来区分用户组,这时候可以预先定义好各组chain,利用VPN服务端软件的一些钩子,当用户登陆时自动添加策略引导到自定义chain上来匹配。如果这时候没有自定义chain,那么策略的数量将是(用户数×所属组策略数),每增加一个用户,都要把所属组的全部策略添加一遍,这样大量的时间花费在策略匹配上,性能下降很快。


各指令的含义


-APPEND -A

1
iptables -A chain firewall-rule

将规则添加到末尾。

一般情况下,iptables 中最后的规则是丢弃所有数据包。

于是使用-A参数添加的规则在丢弃规则后,将不起作用。


-DELETE -D

1
2
3
4
5
iptables -D chain firewall-rule
# 删除对应规则direwall-rule的那一条
# 或
iptables -D chain rulenum
# 删除chain中编号为rulenum的那一条.1表示第一条。

-INSERT -I

1
iptables -I chain [rulenum] firewall-rule.

将firewall-rule添加为chain中的第rulenum条规则,原先的第rulenum条规则及以后的各条顺次+1。如未指定rulenum,则默认为1.


-REPLACE -R

1
iptables -R chain [rulenum] firewall-rule.

将firewall-rule添加为chain中的第rulenum条规则,原先的第rulenum条规则及以后的各条顺次+1。如未指定rulenum,则默认为1.


-LIST -L

1
iptables -L chain [rulenum] firewall-rule.

列出chain或所有chain的第rulenum条规则或所有规则,在-L后再加上–lube-numbers,则显示序号


-LIST-RULES -S

1
iptables -S chain [rulenum] 

打印全部规则


-FLUSH -F

1
iptables -F chain

情况chain(或全部chain)中的规则


-ZERO -Z

1
iptables -Z chain [rulenum] 

清空chain或所有chain的包和字节计数器


-NEW -N

1
iptables -N chain [rulenum] 

创建名称为chain的新链


-DELETE-CHAIN -X

1
iptables -X [chain] 

删除用户自定义chain或所有用户定义的chain,该指令不影响预设规则


-POLICY -P

1
iptables -P chain target 

改变chain的策略为target


-RENAME-CHAIN -E

1
iptables -E old-chain new-chain

将old-chain名更换为new-chain,使得old-chain的规则失效


各参数的含义


-P 代表协议(PROTOCOL)

  • 指明当前规则针对的传输协议(如 TCP、UDP、ICMP 等)
  • 可能的参数值有:tcp, udp, icmp, all
  • 使用 “all” 表示适用于所有协议。而如果在规则中不指定 -p 参数,则默认使用 “all” 参数。一般不使用 “all” 这个值,要么指定某个特定的协议,要么就指定 -p 参数。
  • -p 的参数值既可以用名称(如 tcp)也可以用协议对应的数值(如 6 代表 tcp 协议)
  • /etc/protocols 文件中包含了所有允许的协议名称和相应数值
  • 也可以用长的参数名 –protocol

-S 代表源地址(SOURCE)

  • 指定数据包的源地址
  • 可以是 ip 地址,或者网络地址,或者主机名(hostname)
  • 例如:-s 192.168.1.101 表示针对特定的 ip 地址
  • 对于网络掩码,使用 /mask。例如,“-s 192.168.1.0/24″ 表示网络掩码为 255.255.255.0 的所有 192.168.1.x 地址都匹配。
  • 如果不指定 -s 参数,默认匹配所有源地址
  • 也可以用长参数名 –src 或者 –source

-D 代表目的地址(DESTINATION)

  • 指定数据包的目的地址
  • 使用方式与上面的 “-s” 一样(不同之处仅在于 -s 指源,而 -d 表示目的地址)
  • 也可以用长参数名 –dst 或者 –destination

-J 代表跳转(TARGET)

  • j 的意思是 “jump”(跳转) 到目标
  • 指定当某个数据包满足该规则的时候的就跳转到的下一个处理规则,而不再顺序执行后面的规则判断
  • 可能的值有:ACCEPT, DROP, QUEUE, RETURN,分别表示接受、丢弃、进入队列,返回(跳出,通常是从某个 chain 中跳回到调用该 chain 的上层 chain)
  • 也可以跳转到某个自定义的 chain 中,使用该 chain 的名称做为跳转目标

-I 代表 IN INTERFACE(入站接口)

  • i 表示 “input interface”(输入接口,即,指定网络数据处理的网卡,一般 eth0 即表示第一块有线网卡的外网接口,lo 表示局域网接口)
  • 可以直接理解为 “-i” 表示接口。不过,-i 和 -o 都表示接口,-i 表示输入时的接口,而 -o 特指输出用的接口。
  • 指定数据包进入 INPUT、FORWARD 和 PREROUTING 链时经由的接口。
  • 例如:-i eth0 表示该规则应该针对从 eth0 接口进来的数据包。
  • 如果不指定 -i 参数,则经由系统中所有可用的接口进入的数据包都可以匹配该规则。
  • 也可以使用长参数 –in-interface

-O 代表 OUT INTERFACE(出站接口)

  • o 表示 “output interface”(出站经由接口)
  • 指定发送出去的数据包进入 INPUT、FORWARD 和 PREROUTING 链时经由的接口。
  • 如果不指定 -o 参数,则经由系统中所有可用的接口发出的数据包都可以匹配该规则。
  • 也可以使用长参数 –out-interface

其它防火墙参数选项

上面某些防火墙参数还有属于它自己的参数选项,可以与其配合使用。下面是一些常用的选项。

要使用这些参数选项,需要指定相应的参数,例如,要使用 “–sport” 选项,应该在规则中指定 “-p tcp” (或者 “-p udp”)等参数。

注意:所有这些选项前面都是 –(2个短横线 – )。

–SPORT 表示 SOURCE PORT (源端口,用于 -P TCP, 或者 -P UDP)

  • 默认匹配所有端口(未特别指定时)
  • 可以指定端口号(数字),也可以指定端口名称。例如,默认的 SSH 端口号码为 22,名称为 ssh,可以表示为 “–sport 22″ 或者 “–sport ssh”。
  • /etc/services 文件包含了所有允许的端口名称和对应的端口号码。
  • 在规则中使用号码比使用名称要好(效率高些)
  • 要匹配一个端口范围,使用英文半角冒号(:),如 22:100 匹配从 22 到 100 的所有端口号。
  • 也可以使用长名称 –source-port

–DPORT 表示 DESTINATION PORT (目的端口,-P TCP, 或者 -P UDP)

  • 与 –sport 的用法相同,区别仅在于对象是目的端口
  • 也可以使用长名称 –destination-port

–TCP-FLAGS 表示 TCP FLAGS (用于 -P TCP)

  • 可以使用英文半角逗号(,)来指定多个 TCP 状态标识
  • 可能值有:SYN, ACK, FIN, RST, URG, PSH。可以全用,也可以不用。

–ICMP-TYPE 表示 ICMP TYPE (ICMP 类型,用于 -P ICMP)

  • 当使用 icmp 协议 “-p icmp” 的时候,可以使用 “–icmp-type” 特别指定 ICMP 类型
  • 例如,使用 “–icmp-type 0″ 表示 “Echo Reply”,“–icmp-type 8″ 表示 “Echo”。

添加VIP:

1
ifconfig eth0:1 192.168.1.22 broadcast 192.168.1.2 netmask 255.255.255.0 up

留言與分享

linux基础

分類 后端, linux

Linux 基础操作笔记

1. 文件操作

1.1 创建文件

1
2
3
4
5
# 创建单个文件
touch file

# 批量创建文件(创建love_1_linux.txt到love_10_linux.txt)
touch love_{1..10}_linux.txt

1.2 文件权限查看

1
ls -l  # 详细列表显示文件权限

输出示例:

1
-rw-r--r-- 1 user group 1024 Mar 1 10:00 example.txt

权限字段说明:

1
2
[文件类型][所有者权限][组权限][其他用户权限]
d rwx r-x r-x
  • 文件类型:-普通文件,d目录,l链接文件
  • 权限组成:r读(4) + w写(2) + x执行(1)

2. 帮助系统

1
2
man <command>  # 查看命令手册
man ls # 示例:查看ls命令手册

常用操作键:

  • 空格键:向下翻页
  • q:退出手册
  • /:搜索内容

3. 用户管理

3.1 用户查看命令

1
2
3
4
whoami        # 显示当前用户名
who am i # 显示登录信息
who -m # 同"who am i"
who mom likes # 显示特定用户信息(需实际用户存在)

3.2 用户操作

1
2
3
4
5
6
7
8
9
10
11
# 创建用户(自动创建home目录)
sudo adduser lilei

# 查看已创建用户
ls /home

# 切换用户
su -l lilei # "-l"模拟完整登录环境

# 删除用户及home目录
sudo deluser lilei --remove-home

4. 用户组管理

4.1 用户组查看

1
2
3
4
5
# 查看指定用户所属组
groups shiyanlou

# 查看所有组(按字母排序)
cat /etc/group | sort

/etc/group 文件格式:

1
group_name:password:GID:user_list

4.2 用户组操作

1
2
# 添加用户到组(需要root权限)
sudo usermod -aG sudo lilei # 示例:添加sudo组

5. 权限管理

5.1 文件权限修改

1
2
3
4
5
6
7
8
# 变更文件所有者
sudo chown shiyanlou iphone6

# 变更文件所属组
sudo chgrp group_name file

# 修改所有权限(所有者/组/其他用户)
chmod 755 filename # rwxr-xr-x

5.2 权限数字表示法

权限 数字
r– 4
-w- 2
–x 1
rwx 7 (4+2+1)

6. 文件类型说明

Linux 一切皆文件,主要类型包括:

  • -:普通文件
  • d:目录文件
  • l:符号链接(相当于快捷方式)
  • c:字符设备文件
  • b:块设备文件
  • s:套接字文件
  • p:管道文件

7. 重要补充说明

  1. 目录权限特殊含义:

    • 读权限:可查看目录内容
    • 写权限:可创建/删除文件
    • 执行权限:可进入目录
  2. 新建用户默认会:

    • 创建同名用户组
    • /home下创建用户目录
    • 基本配置文件从/etc/skel复制
  3. sudo权限配置路径:

    1
    2
    /etc/sudoers
    /etc/sudoers.d/

建议后续可补充:

  • 实际权限修改案例
  • 用户组管理实验
  • sudoers文件的配置方法
  • ACL高级权限控制

留言與分享

作者的圖片

Kein Chan

這是獨立全棧工程師Kein Chan的技術博客
分享一些技術教程,命令備忘(cheat-sheet)等


全棧工程師
資深技術顧問
數據科學家
Hit廣島觀光大使


Tokyo/Macau