分类目录归档:运维

ECS布署nginx+nodesjs

ECS布署nginx+nodesjs

代码共享

我是把nodejs的代码目录当成了数据卷。然后nginx加载数据卷。
关键配置如下。

nodejs dockerfile

VOLUME ["/var/app"]

nginx container

"volumesFrom": [
        {
          "sourceContainer": "nodejs",
          "readOnly": true
          }
],

容器通信

brigde的方式有link方式连接。
我用的网络模式是awsvpc, 在awsvpc中可以直接通过localhost通信。
nginx配置示例如下。

upstream nodejs {
    server 127.0.0.1:3000;
    keepalive 256;
}

server {
    listen 80;
    location  /api/ {
        proxy_pass  http://nodejs/api/;
        proxy_set_header   Connection "";
        proxy_http_version 1.1;
        proxy_set_header        Host            $host;
        proxy_set_header        X-Real-IP       $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

        expires 6h;
        add_header Pragma public;
        add_header Cache-Control "public";
        access_log off;
    }
}

需要规避的坑

我原来在nginx在支持2个站点。
通过server_name区分。
但是在ECS中的nginx中,server_name解析出来是localhost。
最后我只能分成两个server。

利用aws服务布署gitlab高可用服务

通过docker搭建镜像

前提是你已经有了docker服务,此处略过。

拉取镜像

sudo docker pull gitlab/gitlab-ce:latest

创建容器

sudo docker run -d -p 8443:443 -p 8081:80 -p 8022:22 \
--name gitlab --restart always \
--volume /home/ubuntu/dockerData/gitlab/config:/etc/gitlab \
--volume /home/ubuntu/dockerData/gitlab/logs:/var/log/gitlab \
--volume /home/ubuntu/dockerData/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce:latest

说明:

  1. 因为我用了nginx使用了80端口,所以起了新端口以mapping 容器内的端口。
  2. /home/ubuntu/dockerData/gitlab/config 等三个目录需要事先创建好。

配置nginx

新建/etc/nginx/conf.d/gitlab.conf文件

server {
        listen 80;
        server_name  gitlab.xxxx.com;
        charset utf-8;

        access_log  /var/log/nginx/gitlab.access_log;
        error_log  /var/log/nginx/gitlab.error_log;
        if ($http_x_forwarded_proto = 'http') {
            return 301 https://$server_name$request_uri;
        }
        location / {
                proxy_pass http://127.0.0.1:8081;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
    }
}

测试

直接访问gitlab.xxxx.com就已经好了,刚进来要求设置管理员密码。管理员是root
不过这里有个问题,就是数据库配置都是默认配置,使用的容器里给你创建好的数据库,如redis、postgresql等。
为了服务的稳定性,现在都要求把web和数据库分离。下面就是相关的配置说明

自定义相关配置

配置文件都在/etc/gitlab/gitlab.rb文件下。对应的宿主机文件是/home/ubuntu/dockerData/gitlab/config/gitlab.rb
修改完了,在docker中运行gitlab-ctl reconfigure即可。

配置域名

创建了一个test项目,结果发现clone地址是http://78638653e348/root/test.git
这显明有问题。

这里需要修改配置文件, 改配置:

external_url "http://gitlab.example.com"

然后reconfigure就好了。
如果你的域名是http的,到此就结束了。

如果你的域名是https的,可能会和我一样遇到502错误。
针对https的配置是

external_url "https://gitlab.example.com"
nginx['listen_port'] = 80
nginx['listen_https'] = false

同样是reconfigure就好了。

邮件发送服务

搜索smtp即可找到对应的配置项。由于我们主要用的aws服务,他提供了SES发送邮件服务。
我们用的是SES相关的配置。其它如QQ邮箱等,可以查看官方文档

gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "email-smtp.region-1.amazonaws.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "IAMmailerKey"
gitlab_rails['smtp_password'] = "IAMmailerSecret"
gitlab_rails['smtp_domain'] = "yourdomain.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['gitlab_email_from'] = 'gitlab@example.com'
gitlab_rails['gitlab_email_reply_to'] = 'noreply@example.com'

说明:
1. 我在配置过程中一开始没有配置gitlab_email_reply_to选项,结果一直报SMTP错误, 554 Transaction failed: Invalid domain name: '78638653e348' 因为我的gitlab默认的gitlab_email_reply_tonoreply@78638653e348。明确指定之后就正常了。
2. 最后发现78638653e348是做为域名配置在/etc/hosts中的。

保存完后:

1. 进入容器

sudo docker exec -it gitlab /bin/bash

2. 使配置生效

gitlab-ctl reconfigure

3. 测试邮件功能

gitlab-rails console

irb(main):003:0> Notify.test_email('xxxx@xxx.com', 'Message Subject', 'Message Body').deliver_now

使用S3存储数据

S3是由aws提供的分布式存储方案。

搜索store可以迅速定位到相关的配置项

gitlab_rails['artifacts_enabled'] = true
gitlab_rails['artifacts_object_store_enabled'] = true
gitlab_rails['artifacts_object_store_remote_directory'] = "artifacts"
gitlab_rails['artifacts_object_store_connection'] = {
  'provider' => 'AWS',
  'region' => 'us-east-1',
  'use_iam_profile' => true
}

测试
在容器中执行命令: gitlab-rake gitlab:artifacts:migrate

Git LFSGitLab uploads按类似设置,都上传到S3。

备份

备份配置文件

配置文件都在/etc/gitlab目录。由于我们把这个目录mapping到了宿主机的/home/ubuntu/dockerData/gitlab/config目录。

创建在/home/ubuntu/dockerData/gitlab/目录上创建backup.sh

backup=$(date "+etc-gitlab-%s.tar")
sudo sh -c 'umask 0077; tar -cf $backup  config';
# backup to S3
aws s3 cp  $backup s3://yourbucket/backups/config/

每次修改了配置文件后,执行sh backup.sh即可。

备份应用数据

此处我把备份直接备份到S3上。

gitlab_rails['backup_keep_time'] = 604800

 gitlab_rails['backup_upload_connection'] = {
   'provider' => 'AWS',
   'region' => 'us-east-1',
   'aws_access_key_id' => 'aws_access_key_id',
   'aws_secret_access_key' => 'aws_secret_access_key'
 }
 gitlab_rails['backup_upload_remote_directory'] = 'yourbucket/backups/data'

执行docker exec -t gitlab gitlab-rake gitlab:backup:create即可创建一份备份

恢复

恢复配置文件

1. 备份下现有的/etc/gitlab配置文件。

sudo mv /home/ubuntu/dockerData/gitlab/config/ /home/ubuntu/dockerData/gitlab/configgitlab.$(date +%s)

2. 用备份好的配置文件恢复配置文件

sudo tar -xf etc-gitlab-1399948539.tar -C /home/ubuntu/dockerData/gitlab/config/

3. 使新的配置文件生效

gitlab-ctl reconfigure

恢复应用数据

1. 把备份文件拷贝到备份目录。

sudo cp 11493107454_2018_04_25_10.6.4-ce_gitlab_backup.tar /home/ubuntu/dockerData/gitlab/data/backups/

2. 停掉连接了数据库的服务。只留下gitlab。

sudo gitlab-ctl stop unicorn
sudo gitlab-ctl stop sidekiq
# Verify
sudo gitlab-ctl status

3. 从备份文件中恢复数据

ls /var/opt/gitlab/backups/ #看下文件名
cd /var/opt/gitlab/backups/ #进入备份目录
sudo gitlab-rake gitlab:backup:restore BACKUP=1493107454_2018_04_25_10.6.4-ce #备份文件名中的_gitlab_backup.tar不需要填写。

4. 重启服务并检查

sudo gitlab-ctl restart
sudo gitlab-rake gitlab:check SANITIZE=true

参考

  1. 利用docker和gitLab搭建git私有服务器
  2. gitlab smtp配置
  3. 配置gitlab通过smtp发送邮件
  4. 使用对象存储
  5. 文件上传使用S3
  6. 使用外部数据库
  7. 备份
  8. 恢复
  9. 配置url
  10. external_url 502

sonar、jenkins构建代码检查

安装sonar

预置条件

1)已安装JAVA环境
    版本:JDK1.8
2)已安装有mysql数据库
    版本:mysql5.6以上
3)下载sonarQube与sonar-scanner
    版本:[sonarQube7.3](https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-7.3.zip)
    版本:[sonar-scanner3.2](https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.2.0.1227-linux.zip)

创建数据库

创建用户sonar:  
CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci;  
CREATE USER 'sonar' IDENTIFIED BY 'sonar';  
GRANT ALL ON sonar.* TO 'sonar'@'%' IDENTIFIED BY 'sonar';  
GRANT ALL ON sonar.* TO 'sonar'@'localhost' IDENTIFIED BY 'sonar';  
FLUSH PRIVILEGES;

请不要用sonar用作密码,这里只是个示例!!!!

创建sonar专用用户

$ useradd sonar
$ passwd sonar

修改配置文件

将sonar-7.3.zip上传到服务器,放置到/home/sonar 目录,并解压到当前目录即可。
修改conf目录下的sonar.properties文件
配置参考:
修改数据库连接及用户名、密码和本机IP
sonar.jdbc.username=
sonar.jdbc.password=
sonar.jdbc.url=jdbc:mysql://IP:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance

sonar.web.host=

启动服务

启动sonar
切换到sonar安装目录下 /bin/linux-x86-64
#./sonar.sh start

现在通过9000端口就可以访问web服务了。
我这里启动出了问题。通过./sonar.sh console可以看到问题是Process exited with exit value [es]: 143另外在logs目录有更详细的错误信息。

解决es问题

  1. max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
$ vim /etc/sysctl.conf
添加vm.max_map_count=262144
$ sysctl -p使配置生效。

配置自启动

创建自启动脚本文件/etc/init.d/sonar

$ vi /etc/init.d/sonar

添加如下内容

#!/bin/sh
#
# rc file for SonarQube
#
# chkconfig: 345 96 10
# description: SonarQube system (www.sonarsource.org)
#
### BEGIN INIT INFO
# Provides: sonar
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Short-Description: SonarQube system (www.sonarsource.org)
# Description: SonarQube system (www.sonarsource.org)
### END INIT INFO

/usr/bin/sonar $*

添加启动服务

$ ln -s $SONAR_HOME/bin/linux-x86-64/sonar.sh /usr/bin/sonar
$ chmod 755 /etc/init.d/sonar
$ sysv-rc-conf  sonar on

如果没有sysv-rc-conf,请安装apt-get install sysv-rc-conf

安装sonar-scanner

scanner在于jenkins 进行集成的作用是:jenkins通过scanner传入要分析的工程,scanner再将这些分析结果,传给sonargube 进行呈现

在sonar目录下直接解压zip文件
unzip sonar-scanner-cli-3.2.0.1227-linux.zip

配置

和sonar配置一样

sonar.host.url=http://192.168.136.144:9000
sonar.login=admin
sonar.password=admin
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar123
sonar.jdbc.url=jdbc:mysql://192.168.136.144:3306/sonar?useUnicode=true&characterEncoding=utf8

加入PATH

修改.bash_profile文件

PATH=$PATH:$HOME/bin:/home/sonar/sonar-scanner-3.2.0.1227-linux/bin

source .bash_profile 后执行sonar-scanner -h 有输出就是好了。

配置jenkins

插件安装

系统管理->插件管理 搜索sonar, 可以看到SonarQube Scanner for Jenkins 安装即可。

配置插件

进入系统管理,会发现多了个SonarQube servers的配置项。先勾选Enable injection of SonarQube server configuration as build environment variables
填上名字和地址,token在刚进入sonar的Web页面时,会让你生成一个,就使用那个。

进入系统管理->Global Tool Configuration
新增SonarQube Scanner.
Name填上sonar-scanner-3.2
SONAR_RUNNER_HOME填上/home/sonar/sonar-scanner-3.2.0.1227-linux
保存。

使用sonar

目前公司的代码用的编程语言有.net, python, nodejs。
我以python为示测试的sonar。
只能选择在构建过程中增加。

配置好Anyalysis properties

sonar.projectKey=testSonar
sonar.projectName=testSonar
sonar.projectVersion=1.0
sonar.language=python
sonar.sources=.
sonar.login=admin
sonar.password=admin
sonar.exclusions=**/*View.java #用于忽略文件

遇到上传失败问题ERROR: Caused by: Broken pipe (Write failed)
看web.log日志发现是com.mysql.jdbc.PacketTooBigException: Packet for query is too large (19560234 > 16777216).
调整一下。

set global max_allowed_packet = 100*1024*1024;

然后重启mysql和sonar就好了。

sonar支持更多语言

下载对应的插件,直接复制到extensions/plugins目录下。
然后重启sonar即可。
我司用到了.netcore, 感觉这个稍微麻烦点。
直接用jenkins里构建步骤中的SonarQube Scanner for MSBuild - Begin AnalysisSonarQube Scanner for MSBuild - End Analysis没有成功。报错ERROR: SonarQube Scanner for MSBuild executable was not found for
安装全局工具dotnet tool install --global dotnet-sonarscanner,参考文档
最后在shell里用脚本成功了。

dotnet sonarscanner begin /k:key /n:name /v:1.0 /d:sonar.login=user /d:sonar.password=password
dotnet build
dotnet sonarscanner end /d:sonar.login=user /d:sonar.password=password

重置mysql密码遇到问题:mysqld_safe Directory ‘/var/run/mysqld’ for UNIX socket file don’t exists

问题背景

今天准备在服务器搭建sonar+jenkins做代码审查。跟着操作,需要安装mysql数据库。
结果安装的时候发现已经安装了,问了圈人,也不知道谁装的。不知道有没有用做它途。记得可以改密码的。操作了一番

  1. stop mysql

    systemctl stop mysql

  2. 跳过安全检查

    /usr/bin/mysqld_safe –skip-grant-tables &

呃。报错了。
mysqld_safe Directory ‘/var/run/mysqld’ for UNIX socket file don’t exists

解决办法

说没有就创建一个试试。

mkdir -p /var/run/mysqld
chown mysql:mysql /var/run/mysqld

然后再试下

/usr/bin/mysqld_safe –skip-grant-tables &

好了

接着修改密码去。

  1. 登陆

    mysql -u root mysql

  2. 更新密码

    update user set Password = PASSWORD(‘root’) where User =’root’; //5.6
    update user set authentication_string = PASSWORD(‘root’) where User =’root’; //5.7

  3. 刷新权限

    FLUSH PRIVILEGES;

搞定。

关于 ImportError: No module named _sqlite3 报错解决方法

今天准备用Flask部署方案(ubuntu):Virtualenv+Supervisor+Nginx 部署应用。

结果在执行python manager db init时死活报错。ImportError: No module named _sqlite3

百度下发现sqlite3在python2.7时自带的。
python3需要自己安装。

于是

1、yum -y install sqlite-devel
2、cd  Python-3.5.2       (python源码安装文件解压后的文件夹)
3、./configure --enable-loadable-sqlite-extensions --prefix=/opt/Python352     (--prefix可加可不加)
4、 make && make install

安装好了。测试下python3 -c ‘import sqlite3’ 没问题。

但是在venv环境下居然还是报错。。再百度,又发现原来是我的python3安装了两个版本。刚重新编译时,安装了一个新版本。而venv引用的是老版本。

删除旧版本。
重新弄venv

virtualenv --no-site-packages venv
source  venv/bin/activate
python -c 'import sqlite3'

搞定。差点就放弃,不用venv了,还好最终搞定了。

 

flask推荐看书Flask Web开发 基于Python的Web应用开发实战

Flask部署方案(ubuntu):Virtualenv+Supervisor+Nginx

首先是概念解释

  1. WSGI服务器,负责我们的app与服务器的交互,常用的有Gunicorn。flask自带的不够健壮,不能用在生产服务器上。
  2. Web服务器,是个HTTP服务器,就相当于tomacat于Java,常用的有Nginx,用作反向代理,负载均衡什么的。

Web服务器中,Nginx是一款面向性能设计的HTTP服务器,相较于Apache、lighttpd具有占有内存少,稳定性高等优势。

部署工具:

  1. Virtualenv,用户创建独立的虚拟的Python运行环境,可以解决版本,依赖等问题。
  2. Supervisor,负责管理应用:应用的开启,关闭,以及多应用的管理等

Virtualenv

安装
sudo pip install virtualenv
使用
#创建虚拟环境
virtualenv venv

#启动虚拟环境
source venv/bin/activat

#停止虚拟环境
deactivate

Supervisor

安装
sudo apt-get install supervisor
使用

配置Supervisor的配置文件的路径:/etc/supervisor/conf.d/*conf , centos是 /etc/supervisord.d/*.ini

cd /etc/supervisor/conf.d/*conf

在这里目录下,我们创建我们应用的配置文件,这样Supervisor才能读取到

sudo vim app.conf

里面的内容输入(内容其实就是执行我们的Python文件):

[program:app]
command = python /home/tengfei/api01/test/TestTo/TODO-orm/app.py


//注,这个配置是和后文中Nginx配置好后对象的9000的转发端口执行的操作
[program:todo]
command = /home/tengfei/api01/test/TestTo/TODO-orm/venv/bin/gunicorn -b 127.0.0.1:9000 app:app
directory = /home/tengfei/api01/test/TestTo/TODO-orm

更改配置文件后,要让supervisor的配置文件生效,执行

supervisorctl reload

启动supervisor:

sudo service supervisor start

重启:

sudo service supervisor restart 

查看supervisor程序当前的状态

sudo supervisorctl

这里面可以使用status指令来查看程序的运行状态

app名字:就是刚才配置配置文件中[program:app]的,比如我这里输入 start app就可以了,以后同上:
start app名字 # 启动app
stop app # 停止app

需要注意的是supervisor发生错误的话,需要它的日志中才能看到

supervisor错误日志地址:
/var/log/supervisor/supervisord.log

参考ubuntu安装和使用supervisor

Ubuntu安装Curl的方法

Nginx

安装
    sudo apt-get update
    sudo apt-get install nginx
    
配置

nginx的也是把程序运行需要的配置文件放到指定的目录下即可

cd /etc/nginx

/etc/nginx子目录下,有两个文件要格外关注关注一下:

sites-available  :可用的配置文件
sites-enabled       :生效的配置文件
    

1:先在sites-available 目录下创建配置文件vim api_app

里面写上:

# api_app内容
server {
        listen 81;

        location /static {
                alias /home/tengfei/api01/test/TestTo/TODO-orm/;
        }

        location / {
                proxy_pass http://127.0.0.1:9000;
        }
}

注,listen 81;:意思是nginx监听的是81端口,我开始监听80端口,结果和默认的冲突了;location /static:是把静态文件转发到后文中的目录下;location /:是把动态请求转发到本机(服务器)的9000端口,上面文件的内容的格式可自行百度。我开始

然后创建软连接到sites-enabled

sudo ln -s ../sites-available/api01_app .

然后重新启动nginx

sudo service nginx reload

//这代表nginx重启成功
 * Reloading nginx configuration nginx                                                       [ OK ] 
    
使用

启动

sudo service nginx restart

重启

sudo service nginx reload
    

查看nginx的状态

sudo service nginx status       
    
    

参考:How To Install Nginx on Ubuntu 14.04 LTS

gunicorn

安装

apt-get install gunicorn

使用

gunicorn -b 0.0.0.0:8080 run:app

尝试在虚拟环境中运行一下程序,看看是否可以成功
//注意下面语句前面的run是指运行的python文件的的名字为run.py的话,执行run:app,如果为app.py那就是app:app

参考文档

Ubuntu 安装mysql和简单操作

“error: command ‘x86_64-linux-gnu-gcc’ failed with exit status 1” in virtualenv

ubuntu下mysql-python模块的安装

how to install the SQLALchemy on the ubuntu?

另外可以用fabric来管理构建和部署。 

Docker Registry服务器部署配置-演道网

Docker Registry服务器部署非常简单,只需要合并运行镜像即可,由于Docker Registry服务器整合很多服务,配置的参数非常多,包括:存储,Redis,Auth,日志,中间件,监控,HTTP,通知,健康检查,代理,兼容性

部署Registry服务器

docker run -d -p 5000:5000 --restart=always --name registry \  
  -v `pwd`/data:/var/lib/registry \
  registry:2

部署服务器非常简单,只需要一条命令,映射5000端口到容器,restart机制为总是,并分配当前目录下的data目录作为容器卷,存储镜像数据,你可以配置HTTPS方式的访问,如果需要配置TSL请参考Docker官方文档,如果是在局域网内访问这个方式即可满足需求

测试Registry服务

在测试之前必须要理解镜像的命名,理解下面的两条命令

docker pull ubuntu  

这个命令是从Docker官方的hub拉取ubuntu镜像,这是简写的方式,完整的命令是这样的docker pull docker.io/library/ubuntu

docker pull localhost:5000/foo/bar  

这个命令是从localhost:5000拉取foo/bar镜像,接下来尝试从Docker Hub拉取镜像并推送到本地的Registry服务器,以Ubuntu为例

从Docker Hub拉取Ubuntu镜像并命名为localhost:5000/ubuntu

docker pull ubuntu && docker tag ubuntu localhost:5000/ubuntu  

推送镜像到本地的Registry服务器

docker push localhost:5000/ubuntu  

删除宿主机的localhost:5000/ubuntu并拉取Registry服务器的ubuntu镜像

docker rmi -f localhost:5000/ubuntu  
docker pull localhost:5000/ubuntu  

配置Registry服务器

配置Registry服务器的方式有两种,一种是在运行容器指定环境变量重写配置文件,另一种是直接映射yaml配置文件,建议使用配置文件的方式,这样迁移方便

环境变量重写配置选项

比如重写配置文件存储选项,文件配置如下所示

storage:  
  filesystem:
    rootdirectory: /var/lib/registry

那么运行Registery容器时就需要指定环境变量REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/somewhere

docker run -d -p 5000:5000 --restart=always --name registry \  
  -v `pwd`/data:/var/lib/registry \
  -e  REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/somewhere \
  registry:2

覆盖配置文件

可以使用挂载卷的方式覆盖配置,个人建议使用这种方式配置

docker run -d -p 5000:5000 --restart=always --name registry \  
             -v `pwd`/config.yml:/etc/docker/registry/config.yml \
             registry:2

挂载当前目录下config.yml覆盖容器的/etc/docker/registry/config.yml文件,下面是整个配置文件,参数非常之多,解释一些常用的

version: 0.1  
log: ## 日志选项  
  level: debug
  formatter: text
  fields:
    service: registry
    environment: staging
  hooks:
    - type: mail
      disabled: true
      levels:
        - panic
      options:
        smtp:## 邮件通知配置
          addr: mail.example.com:25
          username: mailuser
          password: password
          insecure: true
        from: sender@example.com
        to:
          - errors@example.com
loglevel: debug # 即将弃用: 使用Log替代  
storage:##存储选项,  
  filesystem: ## 本地文件系统,也可以是云分布式存储,比如微软Azure,亚马逊S3,swift,OSS
    rootdirectory: /var/lib/registry
    maxthreads: 100 ##最大线程数
auth: #验证HTTPS证书配置  
  silly:
    realm: silly-realm
    service: silly-service
  token:
    realm: token-realm
    service: token-service
    issuer: registry-token-issuer
    rootcertbundle: /root/certs/bundle
  htpasswd:
    realm: basic-realm
    path: /path/to/htpasswd
middleware:##中间件类型有registry,repository,storage四种,每种中间件可以像下面的方式使用  
  registry:
    - name: ARegistryMiddleware
      options:
        foo: bar
  storage:
    - name: ARegistryMiddleware
reporting:##监控,可以使用一些在线的监控工具包括bugsnag,newrelic  
  newrelic:
    licensekey: newreliclicensekey
    name: newrelicname
    verbose: true
http:## 由Nginx提供的HTTP服务,可以把它理解成配置Nginx差不多  
  addr: localhost:5000
  prefix: /my/nested/registry/
  host: https://myregistryaddress.org:5000
  secret: asecretforlocaldevelopment
  relativeurls: false
  tls:
    certificate: /path/to/x509/public
    key: /path/to/x509/private
    clientcas:
      - /path/to/ca.pem
      - /path/to/another/ca.pem
    letsencrypt:
      cachefile: /path/to/cache-file
      email: emailused@letsencrypt.com
  debug:
    addr: localhost:5001
  headers:
    X-Content-Type-Options: [nosniff]
notifications:## 事件通知,当Registry服务器发生拉取,推送等时发送事件到endpoints  
  endpoints:
    - name: alistener
      disabled: false
      url: https://my.listener.com/event
      headers: 
      timeout: 500
      threshold: 5
      backoff: 1000
redis:##这个用过的都懂  
  addr: localhost:6379
  password: asecret
  db: 0
  dialtimeout: 10ms
  readtimeout: 10ms
  writetimeout: 10ms
  pool:
    maxidle: 16
    maxactive: 64
    idletimeout: 300s
health:## 健康检查包括存储驱动,file,http服务,tcp的可用性检查  
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3
  file:
    - file: /path/to/checked/file
      interval: 10s
  http:
    - uri: http://server.to.check/must/return/200
      headers:
        Authorization: [Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==]
      statuscode: 200
      timeout: 3s
      interval: 10s
      threshold: 3
  tcp:
    - addr: redis-server.domain.com:6379
      timeout: 3s
      interval: 10s
      threshold: 3
proxy:## 可以镜像Docker Hub的仓库  
  remoteurl: https://registry-1.docker.io
  username: [username]
  password: [password]
compatibility:  
  schema1:
    signingkeyfile: /etc/registry/key.json

配置文件好长,请根据需求配置

转载自演道,想查看更及时的互联网产品技术热点文章请点击http://go2live.cn

搞懂nginx的rewrite模块 – youyu岁月 – SegmentFault-演道网

之前在配置nginx时,总是遇到rewrite指令的last和break标识的问题,看到的资料大都是last 基本上都用这个 Flag,break 中止 Rewirte,不在继续匹配。看完之后还是有点懵,后来看了下rewrite模块的文档,终于搞懂了,这个模块内容也不是太多,索性整个把这个模块都好好整理下吧

ngx_http_rewrite_module 模块用来使用正则表达式(PCRE)改变请求的URI,返回重定向,并有条件地选择配置。

指令执行顺序

  1. 首先顺序执行server块中的rewrite模块指令,得到rewrite后的请求URI
  2. 然后循环执行如下指令
    > 如果没有遇到中断循环标志,此循环最多执行10次,但是我们可以使用break指令来中断rewrite后的新一轮的循环
    

(1). 依据rewrite后的请求URI,匹配定义的 location 块

(2). 顺序执行匹配到的 location 中的rewrite模块指令

指令

break

Context: server, location, if

停止执行 ngx_http_rewrite_module 的指令集,但是其他模块指令是不受影响的
例子说明

server {
    listen 8080;
    # 此处 break 会停止执行 server 块的 return 指令(return 指令属于rewrite模块)
    # 如果把它注释掉 则所有请求进来都返回 ok
    break;
    return 200 "ok";
    location = /testbreak {
        break;
        return 200 $request_uri;
        proxy_pass http://127.0.0.1:8080/other;
    }
    location / {
        return 200 $request_uri;
    }
}

# 发送请求如下
# curl 127.0.0.1:8080/testbreak
# /other

# 可以看到 返回 `/other` 而不是 `/testbreak`,说明 `proxy_pass` 指令还是被执行了
# 也就是说 其他模块的指令是不会被 break 中断执行的
# (proxy_pass是ngx_http_proxy_module的指令)

if

Context: server, location

依据指定的条件决定是否执行 if 块语句中的内容

if 中的几种 判断条件

  1. 一个变量名,如果变量 $variable 的值为空字符串或者字符串”0″,则为false
  2. 变量与一个字符串的比较 相等为(=) 不相等为(!=) 注意此处不要把相等当做赋值语句啊
  3. 变量与一个正则表达式的模式匹配 操作符可以是(~ 区分大小写的正则匹配, ~*不区分大小写的正则匹配, !~ !~*,前面两者的非)
  4. 检测文件是否存在 使用 -f(存在) 和 !-f(不存在)
  5. 检测路径是否存在 使用 -d(存在) 和 !-d(不存在) 后面判断可以是字符串也可是变量
  6. 检测文件、路径、或者链接文件是否存在 使用 -e(存在) 和 !-e(不存在) 后面判断可以是字符串也可是变量
  7. 检测文件是否为可执行文件 使用 -x(可执行) 和 !-x(不可执行) 后面判断可以是字符串也可是变量

注意 上面 第1,2,3条被判断的必须是 变量, 4, 5, 6, 7则可以是变量也可是字符串

set $variable "0"; 
if ($variable) {
    # 不会执行,因为 "0" 为 false
    break;            
}

# 使用变量与正则表达式匹配 没有问题
if ( $http_host ~ "^star\.igrow\.cn$" ) {
    break;            
}

# 字符串与正则表达式匹配 报错
if ( "star" ~ "^star\.igrow\.cn$" ) {
    break;            
}
# 检查文件类的 字符串与变量均可
if ( !-f "/data.log" ) {
    break;            
}

if ( !-f $filename ) {
    break;            
}

return

Context: server, location, if

return code [text];
return code URL;
return URL;

停止处理并将指定的code码返回给客户端。 非标准code码 444 关闭连接而不发送响应报头。

0.8.42版本开始, return 语句可以指定重定向 url (状态码可以为如下几种 301,302,303,307),
也可以为其他状态码指定响应的文本内容,并且重定向的url和响应的文本可以包含变量

有一种特殊情况,就是重定向的url可以指定为此服务器本地的urI,这样的话,nginx会依据请求的协议$schemeserver_name_in_redirectport_in_redirect自动生成完整的 url (此处要说明的是server_name_in_redirectport_in_redirect 指令是表示是否将server块中的 server_namelisten 的端口 作为redirect用 )

# return code [text]; 返回 ok 给客户端
location = /ok {
    return 200 "ok";
}

# return code URL; 临时重定向到 百度
location = /redirect {
    return 302 http://www.baidu.com;
}

# return URL; 和上面一样 默认也是临时重定向
location = /redirect {
    return http://www.baidu.com;
}

rewrite

Context: server, location, if

rewrite regex replacement [flag];

rewrite 指令是使用指定的正则表达式regex来匹配请求的urI,如果匹配成功,则使用replacement更改URIrewrite指令按照它们在配置文件中出现的顺序执行。可以使用flag标志来终止指令的进一步处理。如果替换字符串replacementhttp://https://$ scheme开头,则停止处理后续内容,并直接重定向返回给客户端。

第一种情况 重写的字符串 带http://

location / {
    # 当匹配 正则表达式 /test1/(.*)时 请求将被临时重定向到 http://www.$1.com
    # 相当于 flag 写为 redirect
    rewrite /test1/(.*) http://www.$1.com;
    return 200 "ok";
}
# 在浏览器中输入 127.0.0.1:8080/test1/baidu 
# 则临时重定向到 www.baidu.com
# 后面的 return 指令将没有机会执行了

第二种情况 重写的字符串 不带http://

location / {
    rewrite /test1/(.*) www.$1.com;
    return 200 "ok";
}
# 发送请求如下
# curl 127.0.0.1:8080/test1/baidu
# ok

# 此处没有带http:// 所以只是简单的重写。请求的 uri 由 /test1/baidu 重写为 www.baidu.com
# 因为会顺序执行 rewrite 指令 所以 下一步执行 return 指令 响应了 ok 

rewrite 的四个 flag

  1. last
    停止处理当前的ngx_http_rewrite_module的指令集,并开始搜索与更改后的URI相匹配的location;
  2. break
    停止处理当前的ngx_http_rewrite_module指令集,就像上面说的break指令一样;
  3. redirect
    返回302临时重定向。
  4. permanent
    返回301永久重定向。
# 没有rewrite 后面没有任何 flag 时就顺序执行 
# 当 location 中没有 rewrite 模块指令可被执行时 就重写发起新一轮location匹配
location / {
    # 顺序执行如下两条rewrite指令 
    rewrite ^/test1 /test2;
    rewrite ^/test2 /test3;  # 此处发起新一轮location匹配 uri为/test3
}

location = /test2 {
    return 200 "/test2";
}  

location = /test3 {
    return 200 "/test3";
}
# 发送如下请求
# curl 127.0.0.1:8080/test1
# /test3
last 与 break 的区别

last 和 break一样 它们都会终止此 location 中其他它rewrite模块指令的执行,
但是 last 立即发起新一轮的 location 匹配 而 break 则不会

location / {
    rewrite ^/test1 /test2;
    rewrite ^/test2 /test3 last;  # 此处发起新一轮location匹配 uri为/test3
    rewrite ^/test3 /test4;
    proxy_pass http://www.baidu.com;
}

location = /test2 {
    return 200 "/test2";
}  

location = /test3 {
    return 200 "/test3";
}
location = /test4 {
    return 200 "/test4";
}
# 发送如下请求
# curl 127.0.0.1:8080/test1
# /test3 

当如果将上面的 location / 改成如下代码
location / {
    rewrite ^/test1 /test2;
    # 此处 不会 发起新一轮location匹配;当是会终止执行后续rewrite模块指令 重写后的uri为 /
    rewrite ^/test2 /more/index.html break;  
    rewrite /more/index\.html /test4; # 这条指令会被忽略

    # 因为 proxy_pass 不是rewrite模块的指令 所以它不会被 break终止
    proxy_pass https://www.baidu.com;
}
# 发送如下请求
# 浏览器输入 127.0.0.1:8080/test1 
# 代理到 百度产品大全页面 https://www.baidu.com/more/index.html;
友情提醒下

此处提一下 在上面的代码中即使将 proxy_pass 放在 带有 breakrewrite上面它也是会执行的,这就要扯到nginx的执行流程了。大家有兴趣可以了解下。

rewrite 后的请求参数

如果替换字符串replacement包含新的请求参数,则在它们之后附加先前的请求参数。如果你不想要之前的参数,则在替换字符串 replacement 的末尾放置一个问号,避免附加它们。

# 由于最后加了个 ?,原来的请求参数将不会被追加到rewrite之后的url后面 
rewrite ^/users/(.*)$ /show?user=$1? last;

rewrite_log

Context: http, server, location, if

开启或者关闭 rewrite模块指令执行的日志,如果开启,则重写将记录下notice 等级的日志到nginxerror_log 中,默认为关闭 off

Syntax:    rewrite_log on | off;

set

Context: server, location, if

设置指定变量的值。变量的值可以包含文本,变量或者是它们的组合形式。

location / {
    set $var1 "host is ";
    set $var2 $host;
    set $var3 " uri is $request_uri";
    return 200 "response ok $var1$var2$var3";
}
# 发送如下请求
# curl 127.0.0.1:8080/test
# response ok host is 127.0.0.1 uri is /test

uninitialized_variable_warn

Context: http, server, location, if

控制是否记录 有关未初始化变量的警告。默认开启

转载自演道,想查看更及时的互联网产品技术热点文章请点击http://go2live.cn

centos7 启用telnet

centos7 启用telnet

1.CentOS 7.0 telnet-server 启动问题
解决方法:
①、先检查CentOS7.0是否已经安装以下两个安装包:telnet-server、xinetd。
命令如下:

# rpm -qa telnet-server 
# rpm -qa xinetd 

如果没有安装,则先安装。
安装命令:

# yum install telnet-server telnet
# yum install xinetd 

安装完成后,将xinetd服务加入开机自启动:

# systemctl enable xinetd.service 

将telnet服务加入开机自启动:

# systemctl enable telnet.socket 

最后,启动以上两个服务即可:

# systemctl start telnet.socket
# systemctl start xinetd(或service xinetd start) 

测试下:

telnet localhost

centos安装ftp服务

1.安装vsftpd组件,安装完后,有/etc/vsftpd/vsftpd.conf 文件,用来配置,还有新建了一个ftp用户和ftp的组,指向home目录为/var/ftp,默认是nologin(不能登录系统)

yum -y install vsftpd

可以用下面命令查看用户

cat /etc/passwd

默认ftp服务是没有启动的,用下面命令启动

service vsftpd start

2.安装ftp客户端组件(用来验证是否vsftpd)

yum -y install ftp

执行命令尝试登录

ftp localhost

输入用户名ftp,密码随便(因为默认是允许匿名的)

登录成功,就代表ftp服务可用了。

但是,外网是访问不了的,所以还要继续配置。

3.取消匿名登陆

vi /etc/vsftpd/vsftpd.conf

把第一行的
anonymous_enable=YES ,改为NO

重启

service vsftpd restart

4.新建一个用户(ftpuser为用户名,随便就可以)

useradd ftpuser

修改密码(输入两次)

passwd ftpuser

这样一个用户建完,可以用这个登录,记得用普通登录不要用匿名了。登录后默认的路径为 /home/ftpuser.

5.开放21端口

因为ftp默认的端口为21,而centos默认是没有开启的,所以要修改iptables文件

vi /etc/sysconfig/iptables

在行上面有22 -j ACCEPT 下面另起一行输入跟那行差不多的,只是把22换成21,然后:wq保存。

还要运行下,重启iptables

service iptables restart

外网是可以访问上去了,可是发现没法返回目录,也上传不了,因为selinux作怪了。

6.修改selinux

getsebool -a | grep ftp

执行上面命令,再返回的结果看到两行都是off,代表,没有开启外网的访问

.... 
allow_ftpd_full_access off 
....
....
ftp_home_dir off

只要把上面都变成on就行

执行

setsebool -P allow_ftpd_full_access 1 
setsebool -P ftp_home_dir off 1

再重启一下vsftpd

service vsftpd restart

这样应该没问题了(如果,还是不行,看看是不是用了ftp客户端工具用了passive模式访问了,如提示Entering Passive mode,就代表是passive模式,默认是不行的,因为ftp passive模式被iptables挡住了,下面会讲怎么开启,如果懒得开的话,就看看你客户端ftp是否有port模式的选项,或者把passive模式的选项去掉。如果客户端还是不行,看看客户端上的主机的电脑是否开了防火墙,关吧)

7.开启passive模式

默认是开启的,但是要指定一个端口范围,打开vsftpd.conf文件,在后面加上

pasv_min_port=30000

pasv_max_port=30999

表示端口范围为30000~30999,这个可以随意改。

改完重启一下vsftpd

由于指定这段端口范围,iptables也要相应的开启这个范围,所以像上面那样打开iptables文件

也是在21上下面另起一行,更那行差不多,只是把21 改为30000:30999,然后:wq保存,重启下iptables。这样就搞定了。