2017年2月24日 星期五

[Docker] CentOS 7 安裝 Docker 教學

一般安裝

// 安裝 epel(Extra Package of Enterprise Linux)
# sudo yum install epel-release

// 安裝 Docker
# sudo yum install docker

// 啟動 Docker
# sudo systemctl start docker

// 開機自動啟動 Docker
# sudo systemctl enable docker

// 下載 ubuntu image 從 docker hub
# sudo docker pull ubuntu:12.04

// 執行 ubuntu 的 bash
# sudo docker run -t -i ubuntu:12.04 /bin/bash

// 列出本機 images
# sudo docker images


指定 Docker 版本安裝

// 移除舊版的 container(或 docker)
# sudo yum -y remove docker docker-common container-selinux docker-selinux

// 安裝 yum-utils
# sudo yum install -y yum-utils

// 加入 docker 的資源庫
# sudo yum-config-manager \
--add-repo \
https://docs.docker.com/engine/installation/linux/repo_files/centos/docker.repo

// 可加入測試版本的 docker
// 使用 yum update 要小心, 會以最新版本進行更新
# sudo yum-config-manager --enable docker-testing

// 也可以取消測試版本
# sudo yum-config-manager --disable docker-testing

// 列出 Docker 的版本
# sudo yum list docker-engine.x86_64  --showduplicates |sort -r

// 安裝 Docker 指定版本
# sudo yum -y install docker-engine-<VERSION_STRING>

// 啟動 Docker
# sudo systemctl start docker

// 開機自動啟動 Docker
# sudo systemctl enable docker

// 下載 ubuntu image 從 docker hub
# sudo docker pull ubuntu:12.04

// 執行 ubuntu 的 bash
# sudo docker run -t -i ubuntu:12.04 /bin/bash

// 列出本機 images
# sudo docker images

參考文件
Docker: https://docs.docker.com/engine/installation/linux/centos/
Git book: https://philipzheng.gitbooks.io/docker_practice/install/centos.html

2016年7月20日 星期三

WYSIWYG HTML editor: CKEditor 4.5.10 + CKFinder 2.6.2 整合圖片上傳



CKEditor 4.5.10


CKFinder 2.6.2

以上兩個套件都可以從官網下載
官網連結如下

CKEditor

CKFinder

都下載好之後解壓縮
放在 / 目錄下
分別取名 ckeditor 跟 ckfinder
另外取名一個 uploads 目錄
讓 ckfinder 可以上傳檔案到該目錄
權限設定 777 (全開)

打開 ckeditor/config.js
在 CKEDITOR.editorConfig 加入以下內容



config.filebrowserBrowseUrl = 'ckfinder/ckfinder.html';
config.filebrowserImageBrowseUrl = 'ckfinder/ckfinder.html?Type=Images';
config.filebrowserFlashBrowseUrl = 'ckfinder/ckfinder.html?Type=Flash';
config.filebrowserUploadUrl = 'ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files'; //可上傳一般檔案
config.filebrowserImageUploadUrl = 'ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Images';//可上傳圖檔
config.filebrowserFlashUploadUrl = 'ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Flash';//可上傳Flash檔案


打開 ckfinder/config.php
找到 function CheckAuthentication()
將 return false; 改成 return true;
找到 $baseUrl 設定上傳目錄
$baseUrl = '/uploads/';

編輯 test.php

<script src="ckeditor/ckeditor.js"></script>

<textarea class="ckeditor" cols="40" id="editor1" name="content" rows="10"></textarea>


啟動 apache
打開 localhost/test.php
就可以正常使用 ckeditor + ckfinder 了!





PHP7: NULL 合併運算式 (Null coalescing operator)

Null 合併運算式 Null coalescing operator

三元運算式(Ternary operator)結合 isset() 的判斷

原本的寫法
$option = (isset($_GET['option'])) ? $_GET['option'] : 'option';

可改成
$option = $_GET['option'] ?? 'option';

也可以加入 $_POST
分別判斷 $_GET['option']  $_POST['option'] 是否存在
$option = $_GET['option'] ?? $_POST['option'] ?? 'option';

很實用的一個功能


2016年4月28日 星期四

Singleton Design Pattern PHP 實作


突然發現自己關於 PHP 的部分寫得很少
補一篇 Singleton Pattern
最簡單也最實用

網路上有篇舉例得很好
說我們建立了一個類別 P
裡面可能呼叫(或載入)了其他的類別(如 C, D, E)
在某些情況下
我們並不希望類別 P 被重複呼叫多次時
類別 C D E 被重複建立
所以才會有這個 Singleton 的策略模式

實作如下
Controller
<?php
Class Test_Controller
{
public $load = null;
public $db = null;
public function __construct()
{
$this->init();
}

private function init()
{
# 載入共用的 loader
$this->load = load::instance();
# 取得 db 連線
$this->db = $this->load->database();
}

public function __destruct()
{
if(@$this->db) $this->db->close();
}
}


Loader
<?php
final class load
{
static $load = null;
static $db = null;
static $api = null;
public static function instance()
{
if(self::$load == null)
{
self::$load = new load();
}
return self::$load;
}
public static function database($host_name = 'test_cloud', $db_name = '')
{
if(self::$db == null)
{
self::$db = new db();
}
return self::$db->$host_name($db_name);
}
}


之後就可以測試看看
當你呼叫(或繼承) Test_Controller 多次之後
load 跟 db 應該都只會有一個實體

以前對於 Singleton 的認知
只是減少了一些不必要的呼叫
對於小公司而言
感受不大

直到目前轉到電商工作之後
才發覺
在大量被訪問的狀況之下
主機的記憶體與DB的連線數
是需要被嚴格控管的
不然硬體在怎麼擴充都不夠

尤其 database transaction 的問題
如果沒有用 Singleton 的話
commit 會亂七八糟的

所以認識 Singleton Pattern 真的是很重要的一件事情
提供給大家參考

2016年4月26日 星期二

RabbitMQ Cluster + HaProxy

RabbitMQ Cluster + HaProxy

套件版本
RabbitMQ 3.6.1
Erlang 18.3
Java JDK 8u91
HaProxy 1.5.14

4台主機
HaProxy   172.20.10.10
MQ_Master 172.20.10.11
MQ_Slave1 172.20.10.12
MQ_Slave2 172.20.10.13

# RabbitMQ Cluster 實作
請參考 RabbitMQ 3.6.1 Cluster 安裝

# HaProxy 安裝
yum install haproxy

# HaProxy 設定
global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

frontend  RabbitmqWeb
    bind *:35672
    mode http
    default_backend             RabbitmqCluster:15672

backend RabbitmqCluster:15672
    log global
    balance     roundrobin
    cookie  SERVERID insert indirect nocache
    server  mq_master 172.20.10.11:15672 inter 10s check cookie s1
    server  mq_slave1 172.20.10.12:15672 inter 10s check cookie s2
    server  mq_slave2 172.20.10.13:15672 inter 10s check cookie s3

listen stats:8888
    bind *:8888
    mode http
stats enable
stats hide-version
stats realm Haproxy\ Statistics
stats uri /
stats auth admin:haproxy
stats refresh 10s

frontend RabbitmqServer
    log global
    bind *:45672
    mode tcp
option tcplog
option logasap
timeout client 168h
    default_backend  RabbitmqCluster:5672

backend RabbitmqCluster:5672
    mode tcp
timeout server 168h
    balance   roundrobin
    server mq_master 172.20.10.11:5672 check inter 1000 fall 3 rise 3
    server mq_slave1 172.20.10.12:5672 check inter 1000 fall 3 rise 3
    server mq_slave2 172.20.10.13:5672 check inter 1000 fall 3 rise 3

# 啟動 HaProxy
systemctl start haproxy
systemctl enable haproxy

# HaProxy 介面
172.20.10.10:8888

# RabbitMQ Web 登入介面
172.20.10.10:35672


# RabbitMQ amqp-lib 設定
define('HOST', '172.20.10.10');
define('PORT', 45672);


2016年4月21日 星期四

RabbitMQ 3.6.1 Cluster 安裝

預備三台機器做 RabbitMQ Cluster
IP 分別為 172.20.10.11~13

套件版本為
RabbitMQ 3.6.1
Erlang 18.3
Java JDK 8u91

# 修改三台 hostname
172.20.10.11$ hostnamectl set-hostname mq_master
172.20.10.12$ hostnamectl set-hostname mq_slave1
172.20.10.13$ hostnamectl set-hostname mq_slave2

# reboot 之後才會生效(以下 all 的動作包含全部的 master & slave)
all$ reboot

# 設定 hosts
all$ vi /etc/hosts

# 加上所有 nodes 的資料
172.20.10.11
172.20.10.12
172.20.10.13

# 安裝 rabbitmq, 作法請參考上一篇的 Centos7 + Rabbitmq
rabbitmq 3.6.1 安裝流程

# 啟動 rabbitmq
all$ rabbitmq-server -detached

# 備份 erlang cookie
all$ cp /root/.erlang.cookie /root/erlang.cookie.bak

# 關閉 rabbitmq(注意, 以下動作包含全部的 slave, 本文則是指 slave1 & slave2)
mq_slave1$ rabbitmqctl stop

# 將 .erlang.cookie 的資料從 mq_master 複製過來(必須是相同的 cookie, 才可加入同一個 cluster)
mq_slave1$ scp root@mq_master:/root/.erlang.cookie /root/

# 啟動 rabbitmq
mq_slave1$ rabbitmqctl start

# 啟動 rabbitmq_management
mq_slave1$ rabbitmqctl enable rabbitmq_management

# 停止 cluster node
mq_slave1$ rabbitmqctl stop_app

# 加入 mq_master 的 cluster
mq_slave1$ rabbitmqctl join_cluster rabbit@mq_master

# 啟動 cluster node
mq_slave1$ rabbitmqctl start_app

# 回到 mq_master 查看 cluster 狀態(重複處理其他的 slave)
mq_master$ rabbitmqctl cluster_status
 # 連到 rabbitmq_management 查看狀態

2016年4月19日 星期二

CENTOS 7 安裝 RabbitMQ 3.6.1

最近要重新架構系統
所以抓了新版的 RabbitMQ 來試試看
跟之前的安裝方式有點不同
不需要在編譯了
步驟簡單很多

安裝套件如下
erlang 18.3
rabbitMQ 3.6.1
php-amqplib 2.6.2

================= 安裝 erlang ==================
# 安裝 ncurses-devel / 核心依賴文件
yum install -y wget unixODBC-devel fop gcc-c++ ncurses-devel openssl-devel autoconf

# 透過 wget 下載 Java JDK(到 www.oracle.com 取得最新的 Java JDK)
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u91-b14/jdk-8u91-linux-x64.rpm"

# 安裝 Java JDK
rpm -ivh jdk-8u91-linux-x64.rpm

# 安裝 erlang / RabbitMQ伺服器是用Erlang語言編寫的 (連至 http://www.erlang.org/download.html 查看最新文件)
wget http://erlang.org/download/otp_src_18.3.tar.gz

# 解壓縮
tar zxvf otp_src_18.3.tar.gz
cd otp_src_18.3

# 組態(可看有那些沒裝好)
./configure

# 建立檔案與安裝(超久)
make && make install

# 測試 erlang 是否安裝成功, "." 為 erlang 的結束符號
erl
9+3.

# halt(). 結束執行
halt().

# 安裝 rabbitMQ
wget https://www.rabbitmq.com/releases/rabbitmq-server/v3.6.1/rabbitmq-server-generic-unix-3.6.1.tar.xz
xz -d rabbitmq-server-generic-unix-3.6.1.tar.xz
tar -xvf rabbitmq-server-generic-unix-3.6.1.tar

# 搬移到 /usr/local/bin 底下管理
mv rabbitmq_server-3.6.1 /usr/local/bin

# 加到 bin 方便操作
ln -s /usr/local/bin/rabbitmq_server-3.6.1/sbin/* /usr/bin

================== rabbitMQ 指令 ==================
# 啟動 rabbitmq-server
rabbitmq-server

# 背景執行
rabbitmq-server -detached

# 新增使用者
rabbitmqctl add_user admin 12345

# 設定管理者權限
rabbitmqctl set_user_tags admin administrator

# 給予管理者權限
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"

================== 安裝 rabbitMQ Management ==================
# 啟動 rabbit_management
rabbitmq-plugins enable rabbitmq_management
rabbitmq-plugins enable amqp_client

# 打開 rabbitmq management 的 port 15672
firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --reload

# 開啟網頁
http://127.0.0.1:15672

================== 安裝 php-amqplib ==================
# 先安裝 php 依賴文件 composer
curl -sS https://getcomposer.org/installer | php

# 安裝 php-bcmath php-mbstring
yum install php-bcmath php-mbstring

# 建立 composer.json
vi composer.json
內容如下
{
  "require": {
      "php-amqplib/php-amqplib": "2.6.*"
  }
}

# 安裝
php composer.phar install


新版的 rabbitmq 畫面保持一貫的簡潔