如何在CentOS 7上安装Nginx

本教程中的步骤要求用户拥有root权限

第一步 – 添加Nginx存储库

要添加CentOS 7 EPEL仓库,请打开终端并使用以下命令:

sudo yum install epel-release

第二步 – 安装Nginx

现在Nginx存储库已经安装在您的服务器上,使用以下yum命令安装Nginx :

sudo yum install nginx

在对提示回答yes后,Nginx将在服务器上完成安装。

第三步 – 启动Nginx

Nginx不会自行启动。要运行Nginx,请输入:

sudo systemctl start nginx

如果您正在运行防火墙,请运行以下命令以允许HTTP和HTTPS通信:

sudo firewall-cmd --permanent --zone=public --add-service=http 
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload

您将会看到默认的CentOS 7 Nginx网页,这是为了提供信息和测试目的。它应该看起来像这样:

未分类

如果看到这个页面,那么你的Web服务器现在已经正确安装了。

如果想在系统启动时启用Nginx。请输入以下命令:

sudo systemctl enable nginx

恭喜!Nginx现在已经安装并运行了!

将安装了CentOS/RHEL 6/7的机器转变成路由器

在本文中,我们将学习通过使用 NAT 技术将安装有 RHEL/CentOS 6 & 7 的机器转变成路由器来用。 我们都知道,路由器是一个工作在第三层的网络设备,用于将两个或多个网络连接在一起,即,将局域网连接上广域网上或者局域网直接互联。 路由器非常昂贵,尤其对于小型组织来说更是如此,这可能是我们关注路由器的一个原因。 与其使用专用硬件,不如让我们用 Linux 机器转换成路由器来用。
RHEL/CentOS 6 和 7 上的操作过程我们都会讲。但在开始之前, 让我们先看看需要准备那些东西。

前期条件

1、一台装有 RHEL/CentOS 6 或 7 的机器

2、两块分别配有本地 IP 和外网 IP 的网卡

我们需要为两个网卡都分配 IP 地址,一个本地网络的 IP(由我们的网络管理员提供),另一个是互联网 IP(由 ISP 提供)。 像这样:

Ifcfg-en0s3 192.168.1.1 (LAN IP address)
Ifcfg-en0s5 10.1.1.1  (WAN IP address)

注意 不同 Linux 发行版的网卡名是不一样的。

现在准备工作完成了,可以进行配置了。

步骤 1 启用 IP 转发

第一步,我们启用 IP 转发。 这一步在 RHEL/CentOS 6 和 7 上是相同的。 运行

$ sysctl -w net.ipv4.ip_forward=1

但是这样会在系统重启后恢复。要让重启后依然生效需要打开

$ vi /etc/sysctl.conf

然后输入下面内容,

net.ipv4.ip_forward = 1

保存并退出。现在系统就启用 IP 转发了。

步骤 2 配置 IPtables/Firewalld 的规则

下一步我们需要启动 IPtables/firewalld 服务并配置 NAT 规则,

$ systemctl start firewalld (For Centos/RHEL 7)
$ service iptables start  (For Centos/RHEL 6)

然后运行下面命令来配置防火墙的 NAT 规则:

CentOS/RHEL 6
$ iptables -t nat -A POSTROUTING -o XXXX -j MASQUERADE
$ service iptables restart 
CentOS/RHEL 7
$ firewall-cmd  -permanent -direct -passthrough ipv4 -t nat -I POSTROUTING -o XXXX -j MASQUERADE -s 192.168.1.0/24
$ systemctl restart firewalld

这里,XXXX 是配置有外网 IP 的那个网卡名称。 这就将 Linux 机器配置成了路由器了, 下面我们就可以配置客户端然后测试路由器了。

步骤 3 配置客户端

要测试路由器,我们需要在客户端的网关设置成内网 IP, 本例中就是 192.168.1.1。 因此不管客户机是 Windows 还是 Linux, 请先确保网关是 192.168.1.1。 完成后, 打开终端或命令行并 ping 一个网站来测试客户端是否能访问互联网了:

$ ping google.com

我们也可以通过网络浏览器访问网站的方式来检查。

如何离线安装ansible

在有网络的情况下,ansible还是很好安装的。但如果你的生产环境有很严格的网络要求,不能够连接外网,你又需要在生产环境上使用ansible。那只有使用离线的方式来安装。但很可惜的是,ansible官方提供的安装包,比如rpm包,并没有包含它所需要的依赖,直接安装是无法使用的。因此需要找个方法自己把所有的依赖解决。

解决的方法有很多,这里列一个比较简单的。首先,找一台能够上网的机器,并且拥有和你的生产服务器有相同linux版本(你的开发环境或测试环境一定有这样的机器)。然后在上头安装对应的工具(二选一):

  • yum-downloadonly
  • Yumdownloader

yum-downloadonly

安装 “downloadonly” 插件:

(RHEL5)
# yum install yum-downloadonly

(RHEL6)
# yum install yum-plugin-downloadonly

在运行yum install时,使用–downloadonly”选项:

yum install --downloadonly --downloaddir=<directory> <package>

确认你需要的package和对应的dependency包已经被保存在了你设置的下载目录。

注意:

  • 在使用插件之前,请检查/etc/yum/pluginconf.d/downloadonly.conf以确认此插件是“enabled = 1”
  • 这仅适用于“yum install / yum update”而不适用于“yum groupinstall”。你可以使用“yum groupinfo”来确认group中的包含软件包,再用yum install下载。
  • 如果仅指定包名称,则下载最新的可用包(如sshd)。否则,您可以指定完整的软件包名称和版本(例如httpd-2.2.3-22.el5)。
  • 如果不使用–downloaddir选项,文件将默认保存在/var/cache/yum/inrhel-{arch}-channel/packages
  • 如果需要,您可以使用相同的命令下载多个软件包。

Yumdownloader

如果你想获取已安装的软件包,那么请使用yumdownloader。

安装yum-utils软件包:

# yum install yum-utils

运行命令,然后运行所需的软件包:

# yumdownloader <package>

注意:

  • 包默认直接保存在当前工作目录中; 也可以使用–destdir选项来指定一个存储位置。
  • 如果您需要下载依赖关系,请务必添加–resolve。

将CentOS升级至最新版本CentOS7.4教程

最近,最新版本的CentOS 7.4发布了。CentOS 7.0,7.1和7.2的所有用户都可以将他们的系统升级到最新版本。

本快速指南将解释您需要更新CentOS或将CentOS升级到最新版本的步骤。

使用“更新”选项,只需一个操作即可将所有CentOS系统软件升级到最新版本。

请注意,yum操作不建议使用“-y”。当然,在允许yum进行之前,您有一些时间来查看要在系统上安装的软件包,方法是使用“yum update”。

在CentOS的早期版本中,我们需要恢复所有的程序和数据,但现在使用CentOS 7,我们可以直接升级,也就是说,意想不到的情况仍然是可能的,因此升级过程之前进行数据备份。

将CentOS升级至最新版本CentOS7.4教程

1. 检查你的CentOS版本。

# cat /etc/redhat-release
CentOS Linux release 7.1.1503 (Core)

2. 备份重要数据和目录(例如:/ etc,/ var,/ opt)

我建议,对于VMware虚拟机,请采用一个好的VMware快照或运行操作系统和数据的完整备份。(MySQL,Apache,NGINX,DNS等),可以查看本站如何备份数据的教程.

3. 用yum更新升级。

# yum clean all
# yum update

4. 用下面的命令重新启动服务器。

# reboot

5. 确认您的系统已成功升级

# cat /etc/redhat-release
CentOS Linux release 7.4.1611 (Core)

我希望这篇文章为您提供一些关于如何更新CentOS或升级CentOS操作系统的想法和基本指导。

未分类

注意:检查您的系统,确保它正常运行,并验证升级之前安装的每个服务。

ansible-playbook组件解析及操作全解

一、ansible-playbook介绍

playbook是由一个或多个”play”组成的列表。play的主要功能在于将事先归为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来将,所谓的task无法是调用ansible的一个module。将多个paly组织在一个playbook中,即可以让他们联通起来按事先编排的机制同唱一台大戏。

1、playbook基础组件

hosts playbook中的每一个paly的目的都是为了让某个或某些以某个指定用户的身份执行任务。hosts用于指定要执行指定任务的主机,其可以是一个或多个由冒号分割主机组。

user remote_user则用于指定远程主机上的执行任务的用户。

任务列表:

play的主体部分是task list. task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。

action

任务执行过程

handlers

用于当前关注的资源发生变化时采取一定指定的操作

2、实例

[root@node1 playbook]# cat web.yml
- hosts: test  \主机组,在/etc/ansible/hosts定义
  remote_user: root  \远端执行任务的用户
  tasks: \任务
  - name: install httpd  \任务描述
    command: yum -y install httpd  \调用ansible的command模块安装httpd
  - name: provide httpd.conf \任务描述
copy: src="/root/httpd.conf" dest="/etc/httpd/conf/httpd.conf" \调用ansible的copy模块,httpd安装完成后将事先准备好的httpd.conf文件复制到/etc/httpd/conf目录下
    tags: conf  \给此任务打标记,可单独执行标记的任务,使用 ansible-playbook -C 命令执行
    notify:  \文件内容变更通知
    - server restart  \通知到指定的任务
  - name: server start  \任务描述
    service: name=httpd state=started enabled=true \调用ansible的service模块的属性定义安装完成httpd以后httpd服务的管理
  handlers: \定义接受关注的资源变化后执行的动作
  - name: server restart  \任务描述
    service: name=httpd state=restarted   \当关注的资源发生变化后调用service模块,采取的响应的动作

执行过程如下:

[root@node1 playbook]# ansible-playbook web.yml 

PLAY [test] ******************************************************************* 

GATHERING FACTS *************************************************************** 
ok: [172.16.2.13]

TASK: [install httpd] ********************************************************* 
changed: [172.16.2.13]

TASK: [provide httpd.conf] **************************************************** 
changed: [172.16.2.13]

TASK: [server start] ********************************************************** 
changed: [172.16.2.13]

NOTIFIED: [server restart] **************************************************** 
changed: [172.16.2.13]

PLAY RECAP ******************************************************************** 
172.16.2.13                : ok=5    changed=4    unreachable=0    failed=0

二、ansible的roles介绍:

ansible的roles用于层次性、结构化地组织palybook。roles能够根据层次型结构自动装载变量文件、tasks及handlers等。要使用roles只需要playbook中使用include指令即可。

rules的组成:

root@node1 playbook]# tree  roles/
roles/ \ansible所有的信息都放到此目录下面对应的目录中
└── nginx  \角色名称
    ├── default  \为当前角色设定默认变量时使用此目录,应当包含一个main.yml文件;
    ├── files  \存放有copy或script等模块调用的文件
    ├── handlers \此目录总应当包含一个main.yml文件,用于定义各角色用到的各handler
    ├── meta \应当包含一个main.yml,用于定义角色的特殊设定及其依赖关系;1.3及以后版本支持
    ├── tasks \至少包含一个名为main.yml的文件,定义了此角色的任务列表,可使用include指令
    ├── templates \template模块会自动在此目录中寻找Jinja2模板文件
    └── vars  \应当包含一个main.yml文件,用于定义此角色用到的变量

roles介绍完了,那么我们就利用ansible的roles来配置nginx

1、首先按照上面的要求创建要用到的目录

[root@node1 playbook]# mkdir -pv roles/nginx/{tasks,files,templates,handlers,vars,meta,default}

2、准备nginx配置文件

准备nginx.conf配置文件,使用模板文件配置

[root@node1 playbook]# cd roles/nginx/templates/
[root@node1 ~]# ansible all -m setup | grep ansible_processor_cores
        "ansible_processor_cores": 1,  \获取ansible的要调用的相关函数
[root@node1 playbook]# cd roles/nginx/templates/   \模板文件一定要放到此目录     
[root@node1 templates]# vim nginx.conf 
worker_processes {{  ansible_processor_cores }};  \调用获取到的函数

准备nginx的default.conf文件

[root@node1 playbook]# ls -l roles/nginx/files/
-rw-r--r--. 1 root root 1290 Nov 12  2014 default.conf

3、准备nginx的rpm包

[root@node1 playbook]# ls -l  roles/nginx/files/
-rw-r--r--. 1 root root   1290 Nov 12  2014 default.conf
-rw-r--r--. 1 root root 319456 Mar 29 20:44 nginx-1.4.7-1.el6.ngx.x86_64.rpm

4、在tasks目录中配置任务列表

[root@node1 playbook]# cd  roles/nginx/tasks/
[root@node1 tasks]# vim  main.yml 
  - name: copy nginx.rpm
    copy: src=nginx-1.4.7-1.el6.ngx.x86_64.rpm  dest=/tmp/nginx-1.4.7-1.el6.ngx.x86_64.rpm
  - name: install nginx
    shell: yum -y  install /tmp/nginx-1.4.7-1.el6.ngx.x86_64.rpm
  - name: provides nginx.conf
    template: src=nginx.conf  dest=/etc/nginx/nginx.conf
    tags: nginxconf
    notify:
    - server restart
  - name: provides default.conf
    copy: src=default.conf dest=/etc/nginx/conf.d/default.conf 
    tags: nginxconf
  - name: server start
    service: name=nginx enabled=true state=started

5、在handlers目录中配置定义handler信息

[root@node1 playbook]# cd roles/nginx/handlers/
[root@node1 handlers]# vim  main.yml 
- name: server restart
  service: name=nginx  state=restarted

6、在roles同一级目录中创建site.yml文件

[root@node1 playbook]# cat site.yml 
- hosts: nginx
  remote_user: root
  roles:
  - nginx

7、应用配置

[root@node1 playbook]# ansible-playbook site.yml 

PLAY [nginx] ****************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [172.16.2.13]

TASK: [nginx | copy nginx.rpm] ************************************************ 
ok: [172.16.2.13]

TASK: [nginx | install nginx] ************************************************* 
changed: [172.16.2.13]

TASK: [nginx | provides nginx.conf] ******************************************* 
changed: [172.16.2.13]

TASK: [nginx | provides default.conf] ***************************************** 
changed: [172.16.2.13]

TASK: [nginx | server start] ************************************************** 
changed: [172.16.2.13]

NOTIFIED: [nginx | server restart] ******************************************** 
changed: [172.16.2.13]

PLAY RECAP ******************************************************************** 
172.16.2.13                : ok=7    changed=5    unreachable=0    failed=0

8、在node2主机上查看nginx是否已启动

[root@node2 ~]# ss -tpln | grep 80
LISTEN     0      128                       *:80                       *:*      users:(("nginx",8934,8),("nginx",8936,8))

9、roles目录总体结构

[root@node1 playbook]# tree roles/
roles/
└── nginx
    ├── default
    ├── files
    │  ├── default.conf
    │  └── nginx-1.4.7-1.el6.ngx.x86_64.rpm
    ├── handlers
    │  └── main.yml
    ├── meta
    ├── tasks
    │  └── main.yml
    ├── templates
    │  └── nginx.conf
    └── vars

Ansible基于服务树进行分组全量接口调用

Ansible APi

说明

品茶:代码是基于我们的服务树结构进行构建,如果需要自己构建相应服务树则可以根据group host inventory进行自行构建。我们中带有中文,所以命令行模式需要2.0才可以调中文,1.9需要改代码。直接调模块不受影响。

Info

ansible2.0更贴近于ansible cli的常用命令执行方式,不同于上一版本只能发送单个命令或playbook;而更推荐用户在调用ansibleAPI的时候,将playbook的每个task拆分出来,获取每个task的结果。能够跟灵活处理在执行批量作业过程中的各种反馈。

Info 2

将执行操作的队列模型,包含各类环境参数设置,归结到“ansible.executor.task_queue_manager”类中
将执行过程中的各个task的设置,或者说playbook中的编排内容,归结到“ansible.playbook.play”中

Import Packge

from collections import namedtuple #有命元组
from ansible.parsing.dataloader import DataLoader #数据解析
from ansible.vars import VariableManager # 变量管旦
from ansible.inventory import Inventory # 主机配置信息
from ansible.playbook.play import Play # 剧本
from ansible.executor.task_queue_manager import TaskQueueManager # 任务消息队列
from ansible.plugins.callback import CallbackBase #回调

Info

  • inventory –> 由ansible.inventory模块创建,用于导入inventory文件
  • variable_manager –> 由ansible.vars模块创建,用于存储各类变量信息
  • loader –> 由ansible.parsing.dataloader模块创建,用于数据解析
  • options –> 存放各类配置信息的数据字典
  • passwords –> 登录密码,可设置加密信息
  • stdout_callback –> 回调函数

Example Code

# #coding:utf8
import json
import sys

from ansible.runner import Runner
from ansible.inventory.group import Group
from ansible.inventory.host import Host
from ansible.inventory import Inventory
from ansible import playbook
from ansible import callbacks
from ansible import utils

from cmdb import groups


class CmdbInventory(object):
    '''
    Get ansible.inventory for cmdb parse tree
    '''

    def __init__(self):

        self.cmdbs = groups()
        self.inventory = self.init_inventory()

    def init_inventory(self, inventory=Inventory(host_list=[])):
        '''

        :param inventory: default param, init cmdb Tree info.
        :return: ansible.inventory type
        '''

        for name in self.cmdbs:
            if name == "_meta": # 主机变量,暂不处理
                pass
            g = Group(name=name)

            # 设置组环境变量
            if self.cmdbs[name].get("vars", None):
                vars = self.cmdbs[name]["vars"]
                for k,v in vars.iteritems():
                    g.set_variable(k, v)

            # 添加主机进主机组
            if self.cmdbs[name].get("hosts", None):
                hosts = self.cmdbs[name]["hosts"]
                for host in hosts:
                    h = Host(name=host)
                    g.add_host(h)

            inventory.add_group(g)

        # 处理子组
        for name in self.cmdbs:
            if self.cmdbs[name].get("children", None):
                children = self.cmdbs[name]["children"]
                for child in children:
                    g = inventory.get_group(name)
                    child = inventory.get_group(child)
                    g.add_child_group(child)

        # 处理主机的环境变量
        hostvars = self.cmdbs.get("_meta",{}).get("hostvars", {})
        if hostvars:
           for host in hostvars:
               inve_host = inventory.get_host(host)
               for k, v in hostvars[host].iteritems():
                   inve_host.set_variable(k, v)

        return inventory

class Ansible(object):
    def __init__(self, transport="paramiko", module_name="ping",
                 module_args="", pattern="", remote_user="",
                 remote_pass="", play_book=False, yml_path=""):
        '''
        Run a ansible task
        :param transport: paramiko, ssh, smart
        :param module_name: ansible module name
        :param module_args: ansible module args
        :param pattern: ansible pattern
        :param remote_user: transport user
        :param remote_pass: transport password
        :return: ansible task result
        '''

        if not remote_user or not remote_pass:
            raise ValueError("Ansible class need params remote_user, remote_pass")

        if play_book:
            if not yml_path:
                raise ValueError("playbook need params yml_path")
        else:
            if not module_name or not pattern:
                raise ValueError("Ad-hoc need params module_name, pattern")

        if transport not in ("paramiko", "ssh", "smart"):
            raise ValueError("params transport not in paramiko, ssh, smart.")

        self.transport = transport
        self.module_name = module_name
        self.module_args = module_args
        self.pattern = pattern.decode("utf-8")  # 这是因为中文问题
        self.remote_user = remote_user
        self.remote_pass = remote_pass
        self.play_book = play_book
        self.yml_path = yml_path

        # A 通过解析方式(这是一种单独的方式)
        # ci = CmdbInventory()
        # inventory = ci.inventory

        # B 通过脚本方式(这是一种全量的方式,可通过修改文件名)
        self.inventory = Inventory(host_list="cmdb.py")

    def task(self):
        '''Ansible Ad-Hoc'''

        try:
            runner = Runner(
                transport=self.transport,
                module_name=self.module_name,
                module_args=self.module_args,
                pattern=self.pattern,
                forks=10,
                inventory=self.inventory,
                remote_user=self.remote_user,
                remote_pass=self.remote_pass
            )
            result =  runner.run()
            return True, result
        except Exception as e:
            return False, str(e)

    def playbook(self):
        stats = callbacks.AggregateStats()
        playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
        runner_cb = callbacks.PlaybookRunnerCallbacks(stats=stats, verbose=utils.VERBOSITY)

        # B 通过脚本方式(这是一种全量的方式,可通过修改文件名)
        inventory = Inventory(host_list="cmdb.py")

        pb = playbook.PlayBook(
            inventory=self.inventory,
            playbook=self.yml_path,
            stats=stats,
            callbacks=playbook_cb,
            runner_callbacks=runner_cb,
            check=True,
            transport=self.transport,
            remote_user=self.remote_user,
            remote_pass=self.remote_pass
        )

        result = pb.run()
        return True, result

if __name__ == "__main__":
    ansible = Ansible(remote_user="",
                      remote_pass="",
                      play_book=True,
                      yml_path="playbooks/ping.yml")
    # result = ansible.task()
    result = ansible.playbook()
    print json.dumps(result, indent=4)

gitlab基本维护和使用

基本介绍

GitLab是一个自托管的Git项目仓库,可以自己搭建个人代码管理的仓库,功能与github类似。

安装

下载 gitlab下载地址: https://about.gitlab.com/downloads/

安装依赖的包

sudo yum install curl-devel
sudo yum install expat-devel
sudo yum install gettext-devel
sudo yum install openssl-devel
sudo yum install zlib-devel
sudo yum install perl-devel
sudo yum install curl
sudo yum install openssh-server
sudo yum install openssh-clients
sudo yum install postfix
sudo yum install cronie

Ubuntu系统使用apt-get方式安装依赖包。

使用gitlab官网的脚本安装

curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash

或者使用gitlab的yum安装gitlab

sudo yum install gitlab-ce

安装完毕后,使用Web登录

技术分享

进入gitlab的管理页面,进行常用的分组,工程,用户等功能点的维护。

技术分享

安装完gitlab后的运维操作

初次配置服务

sudo gitlab-ctl reconfigure

启动服务

sudo gitlab-ctl start

停止服务

sudo gitlab-ctl stop

重启服务

sudo gitlab-ctl restart

检查服务的日志信息

检查redis的日志

sudo gitlab-ctl tail redis

检查postgresql的日志

sudo gitlab-ctl tail postgresql

检查gitlab-workhorse的日志

sudo gitlab-ctl tail gitlab-workhorse

检查logrotate的日志

sudo gitlab-ctl tail logrotate

检查nginx的日志

sudo gitlab-ctl tail nginx

检查sidekiq的日志

sudo gitlab-ctl tail sidekiq

检查unicorn的日志

sudo gitlab-ctl tail unicorn   

检查服务状态

sudo gitlab-ctl status

一般服务状态显示信息

显示格式:

状态 : 进程名称:(进程ID)运行时间(秒);进程的日志服务进程和运行时间

run: gitlab-workhorse: (pid 4752) 10759s; run: log: (pid 1077) 13185s
run: logrotate: (pid 12616) 3557s; run: log: (pid 1079) 13185s
run: nginx: (pid 4764) 10758s; run: log: (pid 1076) 13185s
run: postgresql: (pid 4770) 10757s; run: log: (pid 1073) 13185s
run: redis: (pid 4778) 10757s; run: log: (pid 1072) 13185s
run: sidekiq: (pid 4782) 10756s; run: log: (pid 1075) 13185s
run: unicorn: (pid 4786) 10756s; run: log: (pid 1074) 13185s
状态   说明

run    运行状态
down   服务停止

常见的问题

页面显示500,Whoops, something went wrong on our end.
500

Whoops, something went wrong on our end.

Try refreshing the page, or going back and attempting the action again.

Please contact your GitLab administrator if this problem persists.

如何检查和定位问题?

使用命令检查所有服务的状态

sudo gitlab-ctl status

检查服务状态如下

run: gitlab-workhorse: (pid 4752) 10862s; run: log: (pid 1077) 13288s
run: logrotate: (pid 16553) 59s; run: log: (pid 1079) 13288s
run: nginx: (pid 4764) 10861s; run: log: (pid 1076) 13288s
run: postgresql: (pid 4770) 10860s; run: log: (pid 1073) 13288s
run: redis: (pid 4778) 10860s; run: log: (pid 1072) 13288s
run: sidekiq: (pid 4782) 10859s; run: log: (pid 1075) 13288s
run: unicorn: (pid 4786) 10859s; run: log: (pid 1074) 13288s

定位问题

从服务状态信息中显示数据库postgresql的状态是down,即服务停止。

检查数据库postgresql的运行日志,检查出现什么错误?

$ sudo gitlab-ctl tail postgresql
==> /var/log/gitlab/postgresql/state <==

==> /var/log/gitlab/postgresql/current <==
2017-12-21_02:49:51.42192 FATAL: terminating connection due to administrator command
2017-12-21_02:49:51.42194 FATAL: terminating connection due to administrator command
2017-12-21_02:49:51.42194 LOG: autovacuum launcher shutting down
2017-12-21_02:49:51.42287 FATAL: terminating connection due to administrator command
2017-12-21_02:49:51.42289 FATAL: terminating connection due to administrator command
2017-12-21_02:49:51.42463 LOG: shutting down
2017-12-21_02:49:51.59345 LOG: database system is shut down
2017-12-21_02:50:43.38811 LOG: database system was shut down at 2017-12-21 02:49:51 GMT
2017-12-21_02:50:43.41991 LOG: database system is ready to accept connections
2017-12-21_02:50:43.42055 LOG: autovacuum launcher started

日志显示,数据库的访问权限应该是只有用户本身有读写执行的权限,用户组和其他用户不能有权限。

修改数据库数据的权限后,检查服务运行正常。

了解了问题的定位和解决方式,其他问题也很容易在日志中发现和解决,问题可能是磁盘空间少,用户权限错误或者其他原因。

gitlab管理员密码忘记,怎么重置密码
Gitlab 修改root用户密码

使用rails工具打开终端

sudo gitlab-rails console production

查询用户的email,用户名,密码等信息,id:1 表示root账号

user = User.where(id: 1).first

重新设置密码

user.password = ‘新密码‘
user.password_confirmation = ‘新密码‘ 

保存密码

user.save!

完整的操作ruby脚本

user = User.where(id: 1).first
user.password = ‘新密码‘
user.password_confirmation = ‘新密码‘
user.save!

然后使用重置过的密码重新登录。

git 客户端下载地址:https://git-scm.com/download/win
Linux有关的可以直接yum 安装或者apt-get 安装

Centos: yum install git

Ubuntu: apt-get install git

一种 gitlab 版本管理策略

背景

  • 目前负责小组内源码的版本管理,将目前的我们的源码管理策略做一番梳理和分享,以期共同进步。

流程

  1. 先建立主分支master

  2. Owner基于master建立开发分支xxx-dev-v1,xxx-release-v1,分别是第一期开发版本,第一期发布版本。

  3. xxx-dev-v1供开发人员拉取并开发,功能点开发完成且单元测试通过后,将开发代码提交到xxx-dev-v1上。

  4. 测试人员测试xxx-dev-v1的代码,测试通过后,由本人将xxx-dev-v1的代码合并到xxx-release-v1,待发布。发布前若测试人员发现bug,则重复3、4步。

  5. 发布时,由Owner将xxx-release-v1合并到master分支,合并后master分支打tag,如master> git tag 20171220-v1.0,然后运行自动发布脚本进行发布。

  6. 项目是迭代开发,第一期完成后该进行第二期开发,命名方式相同,依次类推。

  7. 如果在开发V2的过程中,需要紧急修复V1(线上)中的漏洞,则重复3、4、5步,并在最后将master的代码合并到V2上,以保证V2的代码最新;如评估后不紧急,可放在V2中开发。

注意

  1. 务必保证master是线上最新版本。

  2. 可改进的地方:经过一段时间的策略使用,认为目前的问题在于角色分工上不够明确,具体表现在两个问题:(1)开发人员代码开发并提交dev分支后,应该提起dev到release的合并请求,由Owner审核后通过,而不是Owner发起合并(2)测试人员在测试没有bug后应提起release合并到master的请求,而不是由Owner发起合并。

使用 Docker 搭建 Gitlab + Jenkins + SonarQube 的 PHP 持续集成环境

对于开源 PHP 项目,现在比较成熟的一套持续集成方案是使用 Github + TravisCI + StyleCI + Scrutinizer + coveralls,不过这套方案如果想要用于私有项目的话就抓狂了,个个要买套餐,其中很多还不便宜。而且对于公司内使用的项目来说,内部搭建的 Gitlab 方案更为常见,对于这种情况,我们可以使用 Gitlab + Jenkins + SonarQube 来进行代替。

安装 SonarQube

$ docker pull postgres

$ docker run --name db -e POSTGRES_USER=sonar -e POSTGRES_PASSWORD=sonar -d postgres

$ docker pull sonarqube

$ docker run --name sq --link db -e SONARQUBE_JDBC_URL=jdbc:postgresql://db:5432/sonar -p 9000:9000 -d sonarqube

执行完毕上面的命令后通过浏览器进入 SonarQube,默认用户名和密码都是 admin,进去后会有一段引导,里面会让你生成一个 access token,这个后面的配置 Jenkins 时会用到。

如果没有记下来的话,可以点右上角的用户头像里面的 My Account > Security 标签中可以生成一个新的。

配置 Jenkins

Jenkins 需要在全局的 系统设置 里面添加 SonarQube Server,填下对应的访问地址和上一步获取的 access token 即可。服务器地址填写 localhost 可能会有问题,填 ip 会比较好些。

然后需要在 系统管理 的 Global Tool Configuration 菜单中配置 SonarQube Scanner 安装,这个直接选择自动安装就好了,十分方便。

这两步配好之后就到对应的项目配置中添加构建步骤,下拉选择 Execute SonarQube Scanner,然后对于 2.1 版本以上的 SonarQube Scanner 就只需要配置 Analysis properties 这一项就可以了,比较常用的参数包括 sonar.projectKey (用来确定 该项目在 SonarQube 中叫什么名字) 和 sonar.sources=(用来指定需要扫描的目录)。

配完之后选择构建即可,可以去当前构建的 Console Output 里面查看有没有报错,正常执行完成的话,在 SonarQube 项目面板中就可以看到一个新增的命名为配置的 sonar.projectKey 的 项目了。

注意点

  • SonarPHP 自定义检查规则需要用 java 来写扩展,比较新的版本内置了 psr2 的规则基本够用,内置的 Quality Profiles 是可以复制一个出来进行自定义的
  • Sonar 嗅探出的一些问题可能实际上并没有什么影响,比如变量名中含有 ‘pwd’ 等,如果原本使用方式确实合理则可适当忽略

GitLab 升级历程

在完成了GitLab的部署、汉化、备份、恢复后,就要接着考虑gitlab的升级了。接触的这段时间gitlab不断的进行迭代更新,所以如果有实用的新功能或严重的bug修复时,必然要考虑GitLab的更新。

一、下载新版本的RPM包

途径1:通过清华开源镜像站

查看清华开源镜像站,暂时还没有我需要的10.0.4的rpm包。

如果有(比如后面有了10.0.4的包),则直接获取该包。

wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-10.0.4-ce.0.el7.x86_64.rpm

途径2:从官方获取RPM包后上传到/root目录下

官方下载:https://packages.gitlab.com/gitlab/gitlab-ce/

因为要在CentOS7上更新的版本是10.0.4,故找到gitlab-ce-10.0.4-ce.0.el7.x86_64.rpm下载到本地后,通过Bitvise SSH Client工具将rpm包上传到gitlab虚拟机的/root目录下。

说明:从下载速度和方便程度来说,走清华的镜像站的方式更优,但是我2017/10/20想下载gitlab10.0.4时,发现清华的镜像站最新只有10.0.3,故采取“途径2”获取最新的安装包。

二、更新gitlab

2.1 关闭部分gitlab服务

gitlab-ctl stop unicorn
gitlab-ctl stop sidekiq
gitlab-ctl stop nginx

2.2 升级

rpm -Uvh gitlab-ce-10.0.4-ce.0.el7.x86_64.rpm

2.3 重新配置gitlab

gitlab-ctl reconfigure

2.4 重启gitlab

gitlab-ctl restart

使用管理员账户登录后可以看到gitlab的版本号已经从10.0.2升到了10.0.4。

未分类

三、更新汉化补丁

3.1 安装git

yum install -y git

3.2 克隆获取汉化版本库

下载最新的汉化包

cd
git clone https://gitlab.com/xhang/gitlab.git

如果是要下载老版本的汉化包,需要加上老版本的分支,比如今天已经是10.0.4,我依旧想下载10.0.2,可以运行下面的语句。

git clone https://gitlab.com/xhang/gitlab.git -b v10.0.2-zh

3.3 查看该汉化补丁的版本

cat gitlab/VERSION

3.4 停止gitlab服务

gitlab-ctl stop

3.5 切换到gitlab汉化包所在的目录

cd /root/gitlab

3.6 比较汉化标签和原标签,,导出patch用的diff文件到/root下

git diff v10.0.4 v10.0.4-zh > ../10.0.4-zh.diff

3.7 回到/root目录

cd

3.8 将10.0.4-zh.diff作为补丁更新到gitlab中

yum install patch -y
patch -d /opt/gitlab/embedded/service/gitlab-rails -p1 < 10.0.4-zh.diff

3.9 启动gitlab

gitlab-ctl start

3.10 重新配置gitlab

gitlab-ctl reconfigure

使用管理员账户登录后可以看到gitlab已经完成了汉化。

未分类