jenkins做持续集成二

2019年7月25日 2 条评论

上一篇文章完成了jenkins的装和基本配置

新建一个maven的持续集成项目。

注意:maven命令我们在上文最后部分自动安装,配置保存之后并不会立刻安装maven,maven命令工具会在第一次构建maven项目是自动下载安装。

新建项目


配置基本信息

配置源码获取方式为git

遇到的一个错误

 No valid crumb was included in the request

在jenkins 的Configure Global Security下 , 取消“防止跨站点请求伪造(Prevent Cross Site Request Forgery exploits)”的勾选或者使用代理的情况下勾选代理。(如下图)

继续,设置构建触发条件,定时扫描构建

构建前后都可以执行特定的动作如shell脚本,这里演示就省略了。只填入构建命令clean package

报保存配置之后,点立即构建

jenkins就会在后台开始自动构架,这里会显示构建进度,构建完成后红色表示失败,蓝色表示成功,点击可以进去查看日志。

点击console查看日志

如果执行错误可以通过日志查看原因,修改错误后,重新构建

可以看到前面三步有构建失败,查看日志可以发现原因:一个是找不到pom.xml,另一是maven下载不了文件。pom文件需要从工程根目录开始算,加上子文件夹路径即可。

通过查看构建日志, maven报错如下:

Failed to transfer Could not transfer artifact org.springframework.boot:spring-boot-starter-parent:pom:1.4.1.RELEASE from/to central (https://repo.maven.apache.org/maven2): Connect to repo.maven.apache.org:443 [repo.maven.apache.org/151.101.52.215] failed: Connection timed out (Connection timed out)
ERROR: Failed to parse POMs
org.apache.maven.project.ProjectBuildingException: Some problems were encountered while processing the POMs:
[FATAL] Non-resolvable parent POM for com.jege.spring.boot:spring-boot-hello-world:1.0.0.RELEASE: Could not transfer artifact org.springframework.boot:spring-boot-starter-parent:pom:1.4.1.RELEASE from/to central (https://repo.maven.apache.org/maven2): Connect to repo.maven.apache.org:443 [repo.maven.apache.org/151.101.52.215] failed: Connection timed out (Connection timed out) and 'parent.relativePath' points at no local POM @ line 24, column 10

构建失败,是因为jenkins配置了代理,但是自动安装的maven没有设置代理,给maven配置代理之后构建成功。

maven代理配置方法:

检查完毕之后,编辑~/.m2/settings.xml文件,代码如下:添加代理配置如下:

<settings>
   ...
<proxies>
      <proxy>
         <id>my-proxy</id>
         <active>true</active>
         <protocol>http</protocol>
         <host>192.168.10.117</host>
         <port>3267</port>
         <!--
         <username>shihuan</username>
         <password>123456</password>
         <nonProxyHosts>repository.mycom.com|*.google.com</nonProxyHosts>
         -->
      </proxy>
    </proxies>
   ...
</settings>   

proxies下可以配proxy元素,如果你声明了多个proxy元素,则默认情况下第一个被激活的proxy会生效。这里声明 了一个id为my-proxy的代理,active的值为true表示激活该代理,protocol表示使用的代理协议,这里是http。当然,最重要的 是指定正确的代理服务器的ip和端口。

分类: linux 标签: ,

使用docker安装jenkins做持续集成

2019年7月24日 1 条评论

一、jenkins的安装

参考上文docker环境的安装配置完成docker的安装。

无论安装什么软件也就是一条命令的事,jenkins也不例外。

docker pull jenkins/jenkins

docker run -d -p 80:8080 -p 50000:50000 -v jenkins:/var/jenkins_home -v /etc/localtime:/etc/localtime --name jenkins jenkins

  • -d 后台运行镜像 -p 80:8080 将镜像的8080端口映射到服务器的80端口
  • -p 50000:50000 将镜像的50000端口映射到服务器的50000端口
  • -v jenkins:/var/jenkins_home 冒号前面的jenkins表示的是docker卷名,冒号后面的 /var/jenkins_home目录为容器中jenkins工作目录。
  • -v /etc/localtime:/etc/localtime 让容器使用和服务器同样的时间设置。
  • --name jenkins 给容器起一个别名

一定不能修改卷名jenkins,这个卷名是容器自带的存放jenkins文件的地方,如果修改为别的路径就会找不到文件,启动jenkins就会退出。

types-of-mounts

docker 为我们提供了三种不同的方式将数据挂载到容器中:volume、bind mount、tmpfs

volume 方式是 docker 中数据持久化的最佳方式。

  • docker 默认在主机上会有一个特定的区域(/var/lib/docker/volumes/ Linux),该区域用来存放 volume。
  • 非 docker 进程不应该去修改该区域。
  • volume 可以通过 docker volume 进行管理,如创建、删除等操作。
  • volume 在生成的时候如果不指定名称,便会随机生成。

  • volume 在容器停止或删除的时候会继续存在,如需删除需要显示声明。

volume 方式应该是持久化数据的首选方式,我们启动jenkins容器命令中的第二个-v参数是Bind mount,它会覆盖容器中的文件,而volume mount则不会,即如果容器中已有文件,则会将文件同步到主机的目录上 。

二、jenkins的配置

打开浏览器输入http://ip进入Jenkins登录页面。页面会提示你到服务器的指定位置获取初始化密码。

由于我们是在容器里运行的jenkins,需要进入容器去查看 /var/jenkins_home/secrets/initialAdminPassword

docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

在文本框中输入这串密码,点继续

如果是内网,jenkins会报网络连接超时,提示配置代理。

输入代理信息后继续

进入插件安装界面,点击左边的推荐插件 Install suggested plugins 后继续

开始自动安装

创建用后保存并继续,进入首页,可以创建job等任务

默认没有安装maven插件

点击上图中复选框自动重启

安装maven,选择addmaven,然后输入名字,选自动安装,保存

重启jenkins http://ip/restart/

分类: linux 标签:

docker快速入门

2019年7月23日 1 条评论

一、什么是docker

dcoker包括一个命令行程序、一个后台守护进程,以及一组远程服务器。他简化了安装、运行、发布和删除软件。

二、镜像、容器、仓库

镜像,是特殊的文件系统,他包含程序、配置、资源等。

容器,镜像的实例。就像是类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

仓库,用于保存镜像的服务。

三、centos安装docker和docker-compose

注意需要使用 root 账户或者可以使用 sudo 的账户

Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE。

社区版是免费提供给个人开发者和小型团体使用的,企业版会提供额外的收费服务,比如经过官方测试认证过的基础设施、容器、插件等。

社区版按照stable和edge两种方式发布,每个季度更新stable版本,如18.06,18.09;每个月份更新edge版本,如18.09,18.10。

安装docker

1、Docker 要求 CentOS 系统的内核版本高于 3.10 ,查看本页面的前提条件来验证你的CentOS 版本是否支持 Docker 。

通过 uname -r 命令查看你当前的内核版本

 $ uname -r

2、使用 root 权限登录 Centos。确保 yum 包更新到最新。

$ sudo yum update

3、卸载旧版本(如果安装过旧版本的话)

$ sudo yum remove docker  docker-common docker-selinux docker-engine

4、安装依赖

sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2

5、添加docker下载仓库

sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

6、docker安装和验证

# 安装docker-ce
sudo yum install docker-ce

# 启动docker-ce
sudo systemctl start docker

# 验证
sudo docker --version

安装 docker-compose

sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose

docker-compose --version

五、安装过程中可能遇到的错误

Error response from daemon: Get https://index.docker.io/v1/search?q=nginx&n=25: dial tcp: lookup index.docker.io on [::1]:53: read udp [::1]:57785->[::1]:53: read: connection refused

需要配置dns,查看服务器DNS网络配置

vi /etc/resolv.conf

添加
nameserver 8.8.8.8

docker pull nginx
Using default tag: latest
Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: req uest canceled while waiting for connection (Client.Timeout exceeded while await ing headers)

这个问题多是网络连接不好或者没有网络,网络不好可以采用国内镜像,内网用户没有网络可以配置代理。

六、docker代理设置

内网服务器不能直接联网,虽然命令行配置了http_proxy环境变量,但是docker命令行工具读不到,会出现上面的类似错误。需要单独配置docker的代理:

覆盖docker.service file来实现

1. 创建 docker.service.d 目录

$ mkdir -p /etc/systemd/system/docker.service.d

2. 创建HTTP 或者HTTPS 代理文件

HTTP:

vim /etc/systemd/system/docker.service.d/http-proxy.conf

HTTPS:

vim /etc/systemd/system/docker.service.d/https-proxy.conf

由于我这里用的是 “HTTPS”,所以只给大家演示HTTPS代理的配置,对于HTTP代理的修改,非常相似,大家可以参考我最后贴出来的连接。

3. 修改 https-proxy.conf 文件

[Service]
Environment="HTTPS_PROXY=xxx.xxx.xxx.xxx:443" "NO_PROXY=localhost,127.0.0.1,xxx.xxxxxx:5000"

解析:

主要是两点内容:

①  HTTPS_PROXY 将它的值对应到您所希望设置的代理服务地址和端口(例如: HTTPS_PROXY=https://proxy.example.com:443),我这里为了保护隐私,就用xxx代替.

②  NO_PROXY 意味着某些情况下我们不需要使用HTTPS代理来访问,一般这就配置私有仓库的路径(例如:NO_PROXY=localhost,127.0.0.1,mydocker-registry.com:5000

4. 完成修改后保存/刷新

###Flush changes:
#systemctl daemon-reload

###Restart Docker:
#systemctl restart docker

5. 查看修改结果

#systemctl show --property=Environment docker

Environment=HTTPS_PROXY=xxx.xxx.xxx.xxx:443 NO_PROXY=localhost,127.0.0.1,mydocker-registry.com:5000

测试:

七、如何使用Docker加速器

针对Docker客户端版本大于1.10的用户

修改daemon配置文件/etc/docker/daemon.json来使用加速器:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://w5z91a3d.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

八、docker常用命令

docker拉取镜像

docker pull [选项] name[:tag]

docker查看镜像

docker images

创建并启动容器

docker run [options] image [command] [arg...]

docker run -d -p 80:80 --name cn1 nginx

-d 放在后台执行

-p 主机端口:容器端口 将容器的端口映射到主机上,目的是可以直接对外提供访问

--name 指定容器名

查看容器状态

docker ps

验证docker运行正常

进入容器

docker exec -it cn1 bash

对容器的操作,就像普通linux那样。我们定位到/usr/share/nginx/html/目录,列出所有文件:

目录下有50x.htmlindex.html两个文件,我们新建一个test.html

echo "<html><header><title>测试页面</title></header>test</html>" >> test.html

测试之前,先从docker退出来,不能可能会找不到命令

停止容器

docker stop [options] container

停止cn1容器
(也可以指定container id停止容器,docker stop 0e9e817ddb5e) ,不能使用镜像名

查看停止状态容器

容器停止并没有销毁,我们可以使用docker ps -a查看停止状态的容器

重启停止状态的容器

docker start cn1

删除容器

删除容器前,必须先停止容器。删除命令:
docker rm 容器名

再次查看终止状态容器,docker ps -a

容器cn1已经被彻底销毁,销毁的容器不能使用start启动,需要使用run重启运行。

删除镜像

删除命令:
docker rmi -f {repository}:{tag}docker rmi -f {image id}

九、docker 网络

linux使用namespace来进行资源的隔离 ,docker的隔离性;

1、docker的网路类型分为:

Bridge模式:桥接(默认的模式)

host模式:容器将不会获得独立的network namespace,将和主机公用一个;即在docker中使用网络和主机上一样的;

None:不与外界任何东西进行通讯

2、采用Bridge的时候需要和主机通讯,就需要使用端口映射

3、端口映射

主机的8080端口映射到容器中的80端口
$ docker run -d --name cn1 -p 8080:80 nginx  

十、docker常用命令速查

docker ps # 查看正在运行的容器
docker ps -a # 查看所有容器
docker ps -l # 查看最近一次运行的容器

docker create 容器名或者容器ID # 创建容器
docker start [-i] 容器名 # 启动容器
docker run 容器名或者容器ID # 运行容器,相当于docker create + docker start
docker attach 容器名或者容器ID bash # 进入容器的命令行(退出容器后容器会停止)
docker exec -it 容器名或者容器ID bash # 进入容器的命令行
docker stop 容器名 # 停止容器
docker rm 容器名 # 删除容器

docker top 容器名 # 查看WEB应用程序容器的进程
docker inspect 容器名 # 查看Docker的底层信息

分类: linux 标签:

linux通过openssh无密码访问window

2019年7月18日 没有评论

对于习惯了使用ssh连接linux执行命令的用户来说,win10已经提供了新的可能,内置了openssh,windows也可以很容易的提供sshd服务,然后执行powershell。对于win7需要手动安装,本文主要介绍win7安装openssh和linux无密码访问linux执行程序。

win7安装openssh

安装包下载地址:
https://github.com/PowerShell/Win32-OpenSSH/releases

64位系统下载
OpenSSH-Win64.zip

将下载的zip包解压缩到C:\Program Files\OpenSSH

安装sshd服务

PS C:\Windows\system32> cd 'C:\Program Files\OpenSSH '
PS C:\Program Files\OpenSSH> powershell.exe -ExecutionPolicy Bypass -File install-sshd.ps1
[SC] SetServiceObjectSecurity 成功
[SC] ChangeServiceConfig2 成功
[SC] ChangeServiceConfig2 成功
sshd and ssh-agent services successfully installed

添加入站防火墙端口22,允许22端口可访问

PS C:\Program Files\OpenSSH> New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Directio
n Inbound -Protocol TCP -Action Allow -LocalPort 22

win7没这个命令,自己去手动在防火墙配置添加:

控制面板\所有控制面板项\Windows 防火墙\高级设置

打开防火请22端口

启动ssh服务:net start sshd

现在已经可在linx使用密码访问服务了。

linux无密码访问windows

配置文件位置C:\ProgramData\ssh\sshd_config,所在的目录是隐藏目录。打开sshd的配置文件之后,修改如下参数,去掉前面的注释

PubkeyAuthentication yes

注释掉结尾两行

重启sshd

net stop sshd ;net start sshd

Linux生成密钥对:

ssh-keygen -t rsa -f id_rsa

把生成的公钥id_rsa.pub内容添加到windows的
%systemdrive%\Users\<user>\.ssh\authorized_keys (如果文件不存在需要先创建)

linux下面执行 ssh -i .\id_rsa user@host 就可以无密码访问linux了。 或者把id_rsa访问~/.ssh目录下,这样可以直接
ssh user@host

遇到如下错误:

2538868 2019-07-18 10:26:11.645 debug1: userauth_pubkey: test pkalg rsa-sha2-512 pkblob RSA SHA256:6LcR7NR13TTY9qR7G6HumknjLfjyrW/GIX3NfQa13Jg [preauth]
2538868 2019-07-18 10:26:11.645 debug1: trying public key file __PROGRAMDATA__/ssh/administrators_authorized_keys
2538868 2019-07-18 10:26:11.648 Authentication refused.
2538868 2019-07-18 10:26:11.648 Failed publickey for user from 10.1.1.4 port 48402 ssh2: RSA SHA256:6LcR7NR13TTY9qR7G6HumknjLfjyrW/GIX3NfQa13Jg

基本都是 authorized_keys 文件权限设置的不正确

只能 System, Administrators和user 三个用户对
authorized_keys 有所有权限,并且文件的所有者需要是user。

检查文件权限:
icacls %systemdrive%\Users\<user>\.ssh\authorized_keys

ssh客户端配置错误日志输出:

ssh客户端查看日志方式 ,使用参数-vv
ssh -vv

ssh服务器端输出日志方式:

修改配置文件 sshd_config,然后重启sshd

  • SyslogFacility LOCAL0
  • LogLevel to DEBUG (or DEBUG2/DEBUG3 for higher levels of logging

linux环境下权限配置

no 'w' for go anywhere (group or others)
700 for .ssh
600 for .ssh/authorized_keys

chmod go-w /home/your-user
chmod 700  /home/your-user/.ssh
chmod 600  /home/your-user/.ssh/authorized_keys*

这其中很多波折没有一一写出来,linux的日志比较详细,windows要么提示权限不对,要么提示失败,没有具体的错误点提示。微软在github上有很多解释说的很不错,在最后要放弃的时候发现只要把你的authorized_keys文件跟.ssh目录下的其它文件配置一致是不是就能解决问题,一试还真行。

linux查看服务sshd日志在tail -f /var/log/secure

https://github.com/PowerShell/Win32-OpenSSH/wiki/ssh.exe-examples
https://github.com/PowerShell/Win32-OpenSSH/wiki/Troubleshooting-Steps
https://github.com/PowerShell/Win32-OpenSSH/issues/870
https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH
分类: linux 标签:

centos安装powershell

2019年7月17日 没有评论

微软powershell功能很强大,也支持了很多linux命令,对于只停留在cmd的同学可以试试,除了命令行,还可以用来开发图形程序。

powershell并且不绑定在windows,微软开源了代码,在linux也可以安装。利用这个特性,linux就可以通过powershell远程执行windows中的程序。

powershell的安装也非常容易,微软在github上提供了编译好的不同系统的安装包,可以更具自己喜欢的系统来选择。

https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell-6.2.2-1.rhel.7.x86_64.rpm

centos通过rpm方式安装:

wget https://github.com/PowerShell/PowerShell/releases/download/v6.2.2/powershell-6.2.2-1.rhel.7.x86_64.rpm
rpm -ivh  powershell-6.2.2-1.rhel.7.x86_64.rpm 

安装完成之后的测试需要特别注意,网上很多方法都说跟windows类似使用powershell进入,实际上目前已经变成了pwsh

分类: linux 标签:

nginx proxy_pass 配置详解

2019年7月10日 没有评论
语法:proxy_pass URL;
默认值:
上下文:locationif in locationlimit_except

设置被代理的服务器的协议和地址,还可以设置可选的URI。

协议是“http”或者“https”。

地址既可以使用域名或者IP地址加端口(可选)的形式来定义:

proxy_pass http://localhost:8000/uri/;

或使用UNIX域套接字路径来定义。该路径接在“unix”字符串后面,两端由冒号所包围,比如:

proxy_pass http://unix:/tmp/backend.socket:/uri/;

如果解析一个域名得到多个地址,所有的地址都会以轮转的方式被使用。当然,也可以使用upstream来定义地址。

请求URI按下面规则传送给后端被代理服务器:

1.如果proxy_pass使用了URI(下面例子中127.0.0.1地址后面部分,包括只有斜杠的情况),请求路径与loction路径的匹配部分将被替换为proxy_pass中定义的URI:

 
location /name/ {
proxy_pass http://127.0.0.1/remote/;
}

2.如果proxy_pass没有使用URI,发给被代理服务器的请求路径和客户端发情的请求路径相同,不会被修改。

location /some/path/ {
proxy_pass http://127.0.0.1;
}

特殊情况:

1.location使用正则表达式定义路径。这种情况下,指令不应该带有URI。

2.使用rewrite指令改变了URI,但仍使用相同配置处理请求(break):

location /name/ {
rewrite /name/([^/]+) /users?name=$1 break;
proxy_pass http://127.0.0.1;
}

这种情况下,指令设置的URI会被忽略,改变后的URI将被发送给后端服务器。

3.后端服务器的地址,端口和URI中都可以使用变量:

proxy_pass http://$host$uri; 
分类: nginx 标签:

nginx upstream 配置和作用

2019年7月10日 没有评论

配置例子

upstream backend {
    server backend1.example.com       weight=5;
    server backend2.example.com:8080;
    server unix:/tmp/backend3;

    server backup1.example.com:8080   backup;
    server backup2.example.com:8080   backup;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

指令

语法:upstream name { ... }
默认值:
上下文:http

定义一组服务器。 这些服务器可以监听不同的端口。 而且,监听在TCP和UNIX域套接字的服务器可以混用。

例子:

upstream backend {
    server backend1.example.com weight=5;
    server 127.0.0.1:8080       max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;
}

默认情况下,nginx按加权轮转的方式将请求分发到各服务器。 在上面的例子中,每7个请求会通过以下方式分发: 5个请求分到backend1.example.com, 一个请求分到第二个服务器,一个请求分到第三个服务器。 与服务器通信的时候,如果出现错误,请求会被传给下一个服务器,直到所有可用的服务器都被尝试过。 如果所有服务器都返回失败,客户端将会得到最后通信的那个服务器的(失败)响应结果。

语法:server address [parameters];
默认值:
上下文:upstream

定义服务器的地址address和其他参数parameters。 地址可以是域名或者IP地址,端口是可选的,或者是指定“unix:”前缀的UNIX域套接字的路径。如果没有指定端口,就使用80端口。 如果一个域名解析到多个IP,本质上是定义了多个server。

你可以定义下面的参数:weight=number设定服务器的权重,默认是1。max_fails=number设定Nginx与服务器通信的尝试失败的次数。在fail_timeout参数定义的时间段内,如果失败的次数达到此值,Nginx就认为服务器不可用。在下一个fail_timeout时间段,服务器不会再被尝试。 失败的尝试次数默认是1。设为0就会停止统计尝试次数,认为服务器是一直可用的。 你可以通过指令proxy_next_upstream、 fastcgi_next_upstream和memcached_next_upstream来配置什么是失败的尝试。 默认配置时,http_404状态不被认为是失败的尝试。fail_timeout=time设定

  • 统计失败尝试次数的时间段。在这段时间中,服务器失败次数达到指定的尝试次数,服务器就被认为不可用。
  • 服务器被认为不可用的时间段。

默认情况下,该超时时间是10秒。backup标记为备用服务器。当主服务器不可用以后,请求会被传给这些服务器。down标记服务器永久不可用,可以跟ip_hash指令一起使用。

Example:

upstream backend {
    server backend1.example.com     weight=5;
    server 127.0.0.1:8080           max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;

    server backup1.example.com:8080 backup;
}
语法:ip_hash;
默认值:
上下文:upstream

指定服务器组的负载均衡方法,请求基于客户端的IP地址在服务器间进行分发。 IPv4地址的前三个字节或者IPv6的整个地址,会被用来作为一个散列key。 这种方法可以确保从同一个客户端过来的请求,会被传给同一台服务器。除了当服务器被认为不可用的时候,这些客户端的请求会被传给其他服务器,而且很有可能也是同一台服务器。

从1.3.2和1.2.2版本开始支持IPv6地址。

如果其中一个服务器想暂时移除,应该加上down参数。这样可以保留当前客户端IP地址散列分布。

例子:

upstream backend {
    ip_hash;

    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com down;
    server backend4.example.com;
}

从1.3.1和1.2.2版本开始,ip_hash的负载均衡方法才支持设置服务器权重值。

语法:keepalive connections;
默认值:
上下文:upstream

这个指令出现在版本 1.1.4.

激活对上游服务器的连接进行缓存。

connections参数设置每个worker进程与后端服务器保持连接的最大数量。这些保持的连接会被放入缓存。 如果连接数大于这个值时,最久未使用的连接会被关闭。

需要注意的是,keepalive指令不会限制Nginx进程与上游服务器的连接总数。 新的连接总会按需被创建。 connections参数应该稍微设低一点,以便上游服务器也能处理额外新进来的连接。

配置memcached上游服务器连接keepalive的例子:

upstream memcached_backend {
    server 127.0.0.1:11211;
    server 10.0.0.2:11211;

    keepalive 32;
}

server {
    ...

    location /memcached/ {
        set $memcached_key $uri;
        memcached_pass memcached_backend;
    }

}

对于HTTP代理,proxy_http_version指令应该设置为“1.1”,同时“Connection”头的值也应被清空。

upstream http_backend {
    server 127.0.0.1:8080;

    keepalive 16;
}

server {
    ...

    location /http/ {
        proxy_pass http://http_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        ...
    }
}

另外一种选择是,HTTP/1.0协议的持久连接也可以通过发送“Connection: Keep-Alive”头来实现。不过不建议这样用。

对于FastCGI的服务器,需要设置 fastcgi_keep_conn 指令来让连接keepalive工作:

upstream fastcgi_backend {
    server 127.0.0.1:9000;

    keepalive 8;
}

server {
    ...

    location /fastcgi/ {
        fastcgi_pass fastcgi_backend;
        fastcgi_keep_conn on;
        ...
    }
}

当使用的负载均衡方法不是默认的轮转法时,必须在keepalive 指令之前配置。

针对SCGI和uwsgi协议,还没有实现其keepalive连接的打算。

语法:least_conn;
默认值:
上下文:upstream

这个指令出现在版本 1.3.1 和 1.2.2.

指定服务器组的负载均衡方法,根据其权重值,将请求发送到活跃连接数最少的那台服务器。 如果这样的服务器有多台,那就采取有权重的轮转法进行尝试。

嵌入的变量

ngx_http_upstream_module模块支持以下嵌入变量:

$upstream_addr保存服务器的IP地址和端口或者是UNIX域套接字的路径。 在请求处理过程中,如果有多台服务器被尝试了,它们的地址会被拼接起来,以逗号隔开,比如: “192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock”。 如果在服务器之间通过“X-Accel-Redirect”头或者error_page有内部跳转,那么这些服务器组之间会以冒号隔开,比如:“192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock : 192.168.10.1:80, 192.168.10.2:80”。$upstream_response_time以毫秒的精度保留服务器的响应时间,(输出)单位是秒。 出现多个响应时,也是以逗号和冒号隔开。$upstream_status保存服务器的响应代码。 出现多个响应时,也是以逗号和冒号隔开。$upstream_http_...保存服务器的响应头的值。比如“Server”响应头的值可以通过$upstream_http_server变量来获取。 需要注意的是只有最后一个响应的头会被保留下来。

分类: nginx 标签:

nginx rtmp流媒体直播服务器配置

2019年7月9日 没有评论

nginx是一个轻量级的web服务器,通过RTMP模块可以提供流媒体服务。RTMP没有预编译好的包,需要从源码编译。

安装nginx和RTMP模块

本文在ubuntu环境实现。安装前的编译工具准备:

$ sudo apt-get install build-essential libpcre3 libpcre3-dev libssl-dev

下载nginx源码包:

$ wget http://nginx.org/download/nginx-1.15.1.tar.gz

从git上下载RTMP模块源码:

$ wget https://github.com/sergey-dryabzhinsky/nginx-rtmp-module/archive/dev.zip

解压两个压缩包,进入nginx文件夹:

$ tar -zxvf nginx-1.15.1.tar.gz
$ unzip dev.zip
$ cd nginx-1.15.1

编译带有rtmp模块的nginx:

$ ./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-dev
$ make
$ sudo make install

到此,nginx安装完成。默认安装到 /usr/local/nginx, 启动命令

$ sudo /usr/local/nginx/sbin/nginx

测试nginx是否正常工作,使用浏览器打开http://ip/,可以看到 "Welcome to nginx!" 页面。

nginx配置RTMP模块

打开配置文件,位置在/usr/local/nginx/conf/nginx.conf ,添加如下配置:

rtmp {
        server {
                listen 1935;
                chunk_size 4096;

                application live {
                        live on;
                        record off;
                }
        }
}

这个一个最基础的直播流配置,把RTMP流发送给请求者。

重启nginx:

$ sudo /usr/local/nginx/sbin/nginx -s stop
$ sudo /usr/local/nginx/sbin/nginx

测试

1.配置OBS推流

新建一个场景,配置如下:

Streaming Service: Custom
Server: rtmp://<your server ip>/live
Play Path/Stream Key: test

2.播放流

使用VLC v2.1.0以后版本,打开网络流文件,输入rtmp://<your server ip>/live/test 就可以看到视频了!

rtmp完整配置,

分类: nginx 标签:

Redis协议详细规范

2019年6月29日 没有评论

Redis客户端和服务器端通信使用名为 RESP (REdis Serialization Protocol) 的协议。虽然这个协议是专门为Redis设计的,它也可以用在其它 client-server 通信模式的软件上。

RESP 是下面条件的折中:

  • 实现起来简单。
  • 解析速度快。
  • 有可读性。

RESP 能序列化不同的数据类型,例如整型(integers)、字符串(strings)、数组(arrays)。额外还有特殊的错误类型。请求从客户端以字符串数组的形式发送到redis服务器,这些字符串表示要执行的命令的参数。Redis用特定于命令的数据类型回复。

RESP 是二进制安全的,并且不需要处理从一个进程发到另外一个进程的批量数据,因为它使用前缀长度来传输批量数据。 注意:这里概述的协议仅用于客户机-服务器通信。Redis集群使用不同的二进制协议在节点之间交换消息。

网络层

连到Redis服务器的客户端建立了一个到6379端口的TCP连接。

虽然RESP在技术上不特定于TCP,但是在Redis的上下文中,该协议仅用于TCP连接(或类似的面向流的连接,如unix套接字)。

请求-响应模型

Redis接受由不同参数组成的命令。一旦收到命令,就会对其进行处理,并将应答发送回客户端。

这是最简单的模型,但是有两个例外:

  • Redis 支持管道pipelining。所以,客户端可以一次发送多个命令,然后再等待应答。
  • 当一个Redis客户端订阅一个频道,那么协议会改变语义并变成pushprotocol, 也就是说,客户客户端不再需要发送命令,因为服务器端会一收到新消息,就会自动发送给客户端。

除了上面两个例外情况,Redis协议是一个简单的请求-响应协议。

RESP 协议解释

RESP 协议在Redis1.2被引入,直到Redis2.0才成为和Redis服务器通信的标准。这个协议需要在你的Redis客户端实现。

RESP 是一个支持多种数据类型的序列化协议:简单字符串(Simple Strings),错误( Errors),整型( Integers), 大容量字符串(Bulk Strings)和数组(Arrays)。

RESP在Redis中作为一个请求-响应协议以如下方式使用:

  • 客户端以大容量字符串RESP数组的方式发送命令给服务器端。
  • 服务器端根据命令的具体实现返回某一种RESP数据类型。

在 RESP 中,数据的类型依赖于首字节:

  • 简单字符串(Simple Strings): 响应的首字节是 “+”
  • 错误(Errors): 响应的首字节是 “-“
  • 整型(Integers): 响应的首字节是 “:”
  • 大容量字符串(Bulk Strings): 响应的首字节是“$”
  • 数组(Arrays): 响应的首字节是 “*

另外,RESP可以使用大容量字符串或者数组类型的特殊变量表示空值,下面会具体解释。RESP协议的不同部分总是以 “\r\n” (CRLF) 结束。

RESP 简单字符串

简单字符串编码方法: 加号后面跟着一个不包含回车或换行字符的字符串 (不允许出现换行),以CRLF(“\r\n”)结尾。

简单字符串通常被用来传输非二进制安全字符串并且消耗极小。例如,许多redis命令在成功时回复“OK”,即简单字符串用以下5个字节编码:

"+OK\r\n"

为了发送二进制安全的字符串,需要使用RESP的大容量字符串(Bulk Strings)替代。

当Redis返回简单字符串(Simple String)时,客户端lib应该返回去掉首字符加号和结尾CRLF字符的字符串给调用者。

RESP Errors

RESP 有特殊类型来处理错误。errors类型除了首字符是减号 ‘-‘不是加号以外,其它跟简单字符串一样。RESP中简单字符和错误的真正区别是:错误被客户端当作异常处理,组成错误类型的字符串是错误消息自身。

基本格式如下:

"-Error message\r\n"

错误应答只在发生异常时发送,例如,要执行命令的参数数据类型不匹配或者命令不存在等。当收到错误返回时,客户端lib应该抛出一个异常。

错误返回例子:

-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value

从”-“后面第一个单词起,直到第一个空格或者换行,表示返回的错误类型。这是Redis的一种约定,并不是RESP协议的要求。

ERR 是一个通用错误, 而 WRONGTYPE 是表示更具体的错误,意味着客户端在错误的数据类型上执行操作。这被叫做错误前缀(Error Prefix), 使客户端不用依赖具体错误消息就知道返回的错误类型,错误消息可能会随着时间而变化。

客户端实现可能会对不同异常返回不同类型的错误,或者可能提供一种通用的方式来捕获错误,通过以字符串的形式直接返回错误名给调用者。

尽管如此,这种特性不能认为很重要,因为它很少被使用。一小部分客户端的实现可能会返回通用错误条件,例如false。

RESP 整型

整型类型是由以冒号开头,CRLF结尾,中间是字符串形式表示的数字。 例如 “:0\r\n”, 或 “:1000\r\n” 都是整型回复。

很多Redis命令返回RESP整数,像 INCRLLEN 和 LASTSAVE.

返回的整数并没有特别的意义, INCR 返回的是一个递增的数字, LASTSAVE 返回的是Unix时间戳等。返回的整数有效值需要在有符号64位整数范围内。

整型返回也被广泛的用来返回 true 或 false。比如 EXISTS 或 SISMEMBER 命令返回1表示true,返回0表示false。

其它命令像 SADDSREM 和 SETNX 如果操作被执行则返回1,否则返回0。

返回整型回复的命令: SETNXDELEXISTSINCRINCRBYDECRDECRBYDBSIZELASTSAVERENAMENXMOVELLENSADDSREMSISMEMBERSCARD.

RESP 大容量字符串

大容量字符串被用来表示最大512MB长的二进制安全字符串。

大容量字符串编码方式:

  • 美元符 “$” 后面跟着组成字符串的字节数(前缀长度),并以 CRLF 结尾。
  • 实际的字符串数据。
  • 结尾是 CRLF。

所以,字符串 “foobar” 编码如下:

"$6\r\nfoobar\r\n"

空字符串编码格式:

"$0\r\n\r\n"

RESP 大容量字符串(Bulk Strings) 也可以使用一个特殊的用来表示空值的格式表示不存在的值。在这种格式里长度值为-1,数据部分不存在,所以空(Null)用如下方式表示:

"$-1\r\n"

叫做空的大容量字符串Null Bulk String。

客户端API库不应该返回空串,当服务器端响应一个空的大容量字符串时,API库可以返回一个空对象给调用者。例如,Ruby库应该返回 ‘nil’ ,而C库应该返回NULL。 

RESP 数组

客户端使用 RESP 数组发送命令到 Redis 服务端。同样地,某些使用 RESP 数组返回元素集合给客户端的 Redis 命令是应答类型。 LRANGE 命令返回元素列表就是一个例子。

RESP 数组使用如下格式发送:

  • 以星号* 为首字符,接着是表示数组中元素个数的十进制数,最后以 CRLF 结尾。
  • 外加数组中每个 RESP 类型的元素。

空数组表示:

"*0\r\n"

有两个 RESP 大容量字符串”foo” 和”bar”元素的 RESP 数组 :

"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"

在前缀 *<count>CRLF 的后面,组成数组的其它数据类型一个接在另一个后面。 例如包含三个整数的数组编码方式:

"*3\r\n:1\r\n:2\r\n:3\r\n"

数组可以包含混合类型,不一定必须是同一种类型。例如,4个整型和1个大容量字符串编码方式:

*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n

(为了方便阅读,应答分成多行来展示)

第一个行表示 *5\r\n 说明后面有5个应答。这些应答组成一个大的应答一起发送。

空数组的概念也是存在的,另一个表示空值的方式(通常使用大容量空字符串,历史遗留导致有这两种格式)。

例如,当 BLPOP 命令超时,它会返回一个空数组,数组的计数器是-1 :

"*-1\r\n"

当 Redis 返回一个空数组的时候,Redis客户端库API应该返回一个空对象而不是返回一个空数组。 这对区分空列表和其它不同情况(像 BLPOP 命令超时情况)是必要的。

数组的数组也是可行的。例如,一个含有两个数组元素的数组编码方式:

*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n

(为了方便阅读,分成多行来展示).

上面的 RESP 数据类型包含两个数组,一个数组包含三个整数1, 2, 3 ,另一个是简单字符串和一个错误类型。

数组中的空元素

数组中可以有为空的元素。主要使用在Redis应答中,为了表示这个元素丢失并且不是一个空的字符串。当SORT命令使用GET 模式选项,并且特定的key丢失的时会出现这种应答。 含有有空元素的应答数组例子:

*3\r\n
$3\r\n
foo\r\n
$-1\r\n
$3\r\n
bar\r\n

第二个元素是空,客户端库应该返回像下面这样的数据:

["foo",nil,"bar"]

这不是前面提到的异常情况,这只是说明协议的一个例子。

发送命令到Redis服务器

至此,我们已经很熟悉RESP序列化格式,写一个Redis客户端库的实现会变得很容易。我们可以进一步说明客户端和服务端如何交互工作:

  • 客户端发送包含只有大容量字符串的数组给Redis服务器。
  • Redis 服务器给客户端发送任意有效的 RESP 数据类型作为应答。

下面是一个典型的交互过程例子:

客户端发送命令 LLEN mylist 来获取存储在 mylist 键中列表的长读,然后服务器端返回整数应答(C: 代表客户端, S: 代表服务器端).

C: *2\r\n
C: $4\r\n
C: LLEN\r\n
C: $6\r\n
C: mylist\r\n

S: :48293\r\n

为了方便理解我们用换行把协议分成不同部分,实际上客户端发送的是一个整体没有换行:*2\r\n$4\r\nLLEN\r\n$6\r\nmylist\r\n as a whole.

管道和多个命令

客户端可以使用同一个连接发送多个命令。通过管道客户端可以一次写操作发送多个命令,发送下一个命令前不需要等待前一个命令的应答。所有应答可以在最后被读取。

关于管道详细参考 page about Pipelining.

内联命令

有时你手边只能操作telnet 并且需要给Redis 服务器端发送命令。虽然Redis协议是容易实现的,但并不适合用在交互会话。redis-cli 也不是随时都能可用。因此,redis还以一种特殊的方式接受为人类设计的命令,称为内联命令格式。 以下是使用内联命令进行服务器/客户端聊天的示例(服务器聊天以s开头,客户端聊天以c开头)。

C: PING
S: +PONG

以下是返回整数的内联命令的另一个示例:

C: EXISTS somekey
S: :0

基本上,您只需在telnet会话中编写空格分隔的参数。由于统一请求协议中没有以*开头的命令,因此Redis能够检测到这种情况并解析您的命令。

Redis 协议的高性能解析器

虽然redis协议是非常容易被人阅读和实现的,但是它可以以类似于二进制协议的性能来实现。

RESP 使用带前缀的长度来传输批量数据,因此不需要像使用json那样扫描有效负载以查找特殊字符,也不需要引用需要发送到服务器的有效负载。

批量和多批量长度可以使用代码进行处理,代码对每个字符执行单个操作,同时扫描CR字符,如以下C代码:

RESP 使用带前缀的长度来传输大容量数据,因此不需要像使用json那样扫描有效负载以查找特殊字符,也不需要引用需要发送到服务器的有效负载。

大容量和多个大容量长度可以使用代码进行处理,代码对每个字符执行单个操作,同时扫描CR字符,如以下C代码:

#include <stdio.h>

int main(void) {
    unsigned char *p = "$123\r\n";
    int len = 0;

    p++;
    while(*p != '\r') {
        len = (len*10)+(*p - '0');
        p++;
    }

    /* Now p points at '\r', and the len is in bulk_len. */
    printf("%d\n", len);
    return 0;
}

在识别出第一个CR之后,可以跳过它和下面的LF,而不需要任何处理。然后,可以使用不以任何方式检查有效负载的单个读取操作读取大容量数据。最后,剩余的CR和LF字符将被丢弃,而不进行任何处理。

Redis协议有着与二进制协议可比的性能,更重要的是易于在大多数高级语言中实现,从而减少了客户端软件中的错误数量。

分类: redis 标签:

spring boot eclipse 下pom文件第一行报unknown错

2019年6月28日 没有评论

从spring.io生成的maven工程,导入eclipse之后pom文件第一行出现unknown错误。

虽然报错,但是工程可以正常用 mvn 命令构建和运行。

查了一下有很多人说不同办法,升级eclipse插件、升级maven版本、删除本地maven库等等。都不太好使,最后发现只有降低spring boot版本号才好使。

如果想用新版本可以使用命令行来构建工程,忽略pom错误。

解决办法:

把spring boot 版本修改成低版本2.1.1.RELEASE就没有unknown错误提示,很神奇。

分类: java 标签: