2019年2月28日 星期四

Redis 心得

https://stackoverflow.com/questions/16613580/redis-how-to-access-keys-in-specific-keyspace
指定keyspace
$ redis-cli -n 1 KEYS '*'
獲取key值
127.0.0.1:6379[1]> GET "laravel_cache:App\\Models\\User:15"
xxx
亦可下載redis gui管理工具: redis desktop manager

使用Redis鎖處理併發問題

redis命令
> SET lockKey value NX EX 30
NX -- 當key不存在時才能設置
NX -- Only set the key if it does not already exist. - "SET if Not eXists" 
EX seconds -- 設置過期時間(秒)
EX seconds -- Set the specified expire time, in seconds.

邏輯

try {
    if (! $lock = RedisLock::lock('do-some-thing', 100000)) {
        throw new Exception('Resource locked.');
    }
    // 業務邏輯
} catch (Exception $e) {
    throw $e;
} finally {
    RedisLock::unlock($lock);
}

實現

$time = microtime();
$max = 1000; //1 second

do {  //针对问题1,使用循环
    $timeout = 10;
    $roomid = 10001;
    $key = 'room_lock';
    $value = 'room_'.$roomid;  //分配一个随机的值针对问题3
    $isLock = Redis::set($key, $value, 'ex', $timeout, 'nx');//ex 秒
    if ($isLock) {
        if (Redis::get($key) == $value) {  //防止提前过期,误删其它请求创建的锁
            //执行内部代码
            Redis::del($key);
            continue;//执行成功删除key并跳出循环
        }
    } else {
        usleep(5000); //睡眠,降低抢锁频率,缓解redis压力,针对问题2
    }
} while(!$isLock && ((microtime() - $time) < $max) );

綠色:限制時間,避免等太久
__destruct() 可能要解鎖,避免「內部代碼」異常一直鎖著

laradock中容器連host的redis報錯

https://blog.51cto.com/crfsz/1878137  redis解决(DENIED Redis is running in protected mode because prote)
DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.

原因

redis 的protected mode被開啟

解法

編輯 /etc/redis.conf  
protected-mode yes  => protected-mode no
重啟redis
# service redis restart

檢查

# redis-cli
127.0.0.1:6379> CONFIG GET protected*
1) "protected-mode"
2) "no"



參考資料:

https://blog.csdn.net/iastro/article/details/83304188  redis锁处理并发问题
https://www.jianshu.com/p/81b0f1bd1328  Redis锁机制的几种实现方式
https://github.com/ginnerpeace/laravel-redis-lock/blob/master/src/Processor.php  laravel-redis-lock


2019年2月18日 星期一

Gitlab+Jenkins實現自動部署

1. 安裝(使用yum安裝,略)

jenkins 2.150.1
gitlab ( GitLab Community Edition 11.5.0 )

2. 配置gitlab

打開project、配置SSH密鑰、上傳code(略)

3. 配置Jenkins

a. 新增插件

Manage Jenkins => Manage Plugins => 安裝以下插件
Gitlab Hook
Build Authorization Token Root
Publish Over SSH
Gitlab Authentication
Gitlab

添加完插件重啟jenkins,開始添加要部署代碼的主機,注意一定是要能夠ssh登陸的用户

b. 添加主機

Manage Jenkins => Configure System => Publish over SSH

c. 新建任務

New Item => (填寫任務名字)Freestyle project => Source Code Management
Build Triggers
Build
Exec command:
# 重啟nginx
/usr/local/nginx/sbin/nginx -s reload
# 同步.git 目錄(git log)
rsync -r /var/lib/jenkins/workspace/test/.git /path/test/jenkins_cd
# 切到develop分支
git --git-dir=/path/test/jenkins_cd/.git remote update
git --git-dir=/path/test/jenkins_cd/.git branch -D develop
git --git-dir=/path/test/jenkins_cd/.git checkout -b develop remotes/origin/develop

4. 配置gitlab,當有代碼提交時,觸發jenkins的部屬操作


出現Hook executed successfully: HTTP 200 => 說明配置成功

5. 加入git-flow

test-release (預發佈分支的jenkins item)

Source Code Management
Branches to build - Branch Specifier (blank for 'any'): */master => 從master生release分支
Build Triggers
Allowed branches - Filter branches by regex - Target Branch Regex: .*master
Build
SSH Publishers - Transfers - Remote directory: /path/test/jenkins_release
SSH Publishers - Transfers - Exec command:
/usr/local/nginx/sbin/nginx -s reload
# 同步 release worksapce的git log 到release項目路徑上
rsync -r /var/lib/jenkins/workspace/test-release/.git /path/test/jenkins_release
# 切換到release 分支
git --git-dir=/path/test/jenkins_release/.git remote update
git --git-dir=/path/test/jenkins_release/.git branch -D release
git --git-dir=/path/test/jenkins_release/.git checkout -b release remotes/origin/master
# 配置.git目录权限
chmod 777 -R /path/test/jenkins_release/.git/


test-master(線上分支的jenkins item)

Source Code Management
Branches to build - Branch Specifier (blank for 'any'): */master
Build Triggers
Allowed branches - Filter branches by regex - Target Branch Regex: .*master
Build
SSH Publishers - Transfers - Remote directory: /path/test/jenkins_master
SSH Publishers - Transfers - Exec command:
/usr/local/nginx/sbin/nginx -s reload
# 同步 master worksapce的git log 到master項目路徑上
rsync -r /var/lib/jenkins/workspace/test-master/.git /path/test/jenkins_master
# 可以使用一些jenkins中的變量
echo "$PWD bear $JOB_NAME-$BUILD_NUMBER $GIT_COMMIT $GIT_PREVIOUS_COMMIT $GIT_PREVIOUS_SUCCESSFUL_COMMIT start" >> /tmp/bear2
# 可以使用bash的條件判斷
if [ "$GIT_COMMIT" = "$GIT_PREVIOUS_COMMIT" ]
then
    echo "var is 123"  >> /tmp/bear2
else
    echo "var is 456"  >> /tmp/bear2
fi
# 切換到master分支
git --git-dir=/path/test/jenkins_master/.git remote update
git --git-dir=/path/test/jenkins_master/.git branch -D master
git --git-dir=/path/test/jenkins_master/.git checkout -b master remotes/origin/master
# 合併release分支內容
git --git-dir=/path/test/jenkins_master/.git --work-tree=/path/test/jenkins_master/ merge remotes/origin/release
# 更新到倉庫的master分支
git --git-dir=/path/test/jenkins_master/.git push origin master:master
# 删除release远程分支
git --git-dir=/path/test/jenkins_master/.git push origin --delete release
# 删除release环境
rm -rf /path/test/jenkins_release/*
rm -rf /path/test/jenkins_release/.git//

ps. test-release、test-master皆需配gitlab webhook

6. 流程

開發在本地環境開發完+自測後更新到develop分支,jenkins會自動部屬測試環境給測試測,測試測完build test-release環境(從master分支分出來的),release環境只有一個,兩人同時要上時必須等待,開發上release環境將develop分支中的commit cherry-pick到release分支中,測試測完release後更新到release分支,線上發佈時build test-master,部屬完更新到master分支、刪除倉庫release分支、release環境

7. Jenkins 建置狀態回寫gitlab

a. 安裝gitlab、jenkins安裝gitlab plugin


b. Gitlab 使用者設定

GitLab 主畫面開啟帳號圖像下拉選單,依序點選「Settings」 → 「Access Tokens」
產生一個Personal Access Tokens
然後你就可以用這個token存取gitlab api
ex. http://gitlab.server.com/api/v4/projects?private_token=xxx

c. Jenkins 設定

Manage Jenkins => Configure System => Gitlab
Gitlab區塊輸入「Connection name」與「Gitlab host URL」
於「Credentials」旁按下【Add】 → 【Jenkins】,開啟「新增 Credentials」頁面
然後填入以下欄位(API token為你剛剛在gitlab生成的access tokens)

d. 工作組態設定

test item => Configure
General
GitLab Connection: 選擇 Gitlab
Post-build Actions
按下【Build Now】,此時此項工作會進行建置並使用 GitLab connection 將建置狀態發送至 GitLab 上。

8. 可能的報錯

a. Gitlab webhook 報錯: 500 Internal Server Error - URI::InvalidURIError

使用root登入gitlab => Admin area => Settings => Network => Outbound requests => 勾選「Allow requests to the local network from hooks and services」
ps. 可能會因為gitlab 版本不同,而菜單位置有差異

b. 永遠使用英文介面

因為jenkins 預設文字為用戶瀏覽器語言,但是網路上查到的資料都是英文的,如何使介面為英文?
i. Jenkins安裝 Locale Plugin
ii. Jenkins configuration => Locale => Default Language: en

參考資料:

https://hk.saowen.com/a/286fcee36ef6c80c697b392adeb8249047a9c282b50fe82b42526af3f673562a  Gitlab+Jenkins實現自動部署(主要)
https://dotblogs.com.tw/echo/2018/04/29/jenkins_plugin_gitlab_publishbuildstatus  【Jenkins】外掛套件:GitLab(Jenkins 建置狀態回寫)(次要)
https://linuxize.com/post/how-to-install-jenkins-on-centos-7/  How To Install Jenkins on CentOS 7
https://web.devdon.com/archives/10  GitLab搭配Jenkins實現可持續集成開發
https://blog.csdn.net/u010947098/article/details/61922969  jenkins使用publishover ssh插件连接应用机器时,报Message [Auth fail]的问题(jenkins.plugins.publish_over.BapPublisherException: Failed to connect and initialize SSH connection. Message: [Failed to connect session for config [测试机]. Message [Auth fail]])
https://stackoverflow.com/questions/49626860/gitlab-webhook-get-error-500-internal-server-error-uriinvalidurierror  Gitlab webhook get error: 500 Internal Server Error - URI::InvalidURIError
https://stackoverflow.com/questions/1386291/git-git-dir-not-working-as-expected  git --git-dir not working as expected
https://stackoverflow.com/questions/12350707/jenkins-in-windows-shows-ui-in-russian-language  Jenkins in Windows shows UI in russian language
https://alexbilbie.com/2015/04/setting-up-jenkins/  Setup Jenkins and test a PHP project