Sunday

22 March, 2020

AWS Client VPN with openSUSE leap 15.1 小記

AWS Client VPN with openSUSE leap 15.1 小記

OS: container with openSUSE Leap 15.1

OS: openSUSE Leap 15.1

之前就有看到 AWS Client VPN 的文章, 但是沒有時間來進行 Lab

想法: 
  • 透過 AWS Client VPN 可以使用桌機或是筆電接入 AWS VPN 的內網, 達成在本機使用 Ansible 進行 AWS 上面的資源調整或是佈署. 
  • 因為不是所有的resource 都有 public IP, 另外也不一定要想要弄台跳板機, 或是把 playbook 放在上面


使用 container 來建立相關步驟的原因
  • 確保有相關 cli 環境, 例如 aws cli / gcloud / az
  • 建立過程中如果有本機不需要的套件需要安裝, 不會影響到本機
  • 也可以用本機來進行建立過程


==== 在主機上面 ====

啟動 container

> docker  run  -v  ~/.aws:/root/.aws -v  ~/.azure:/root/.azure  -v ~/.config/gcloud:/root/.config/gcloud  -v  ~/.ssh:/root/.ssh  -it  sakana/ansible_opensuse151  /bin/bash

  • 這邊也可以考慮掛載一個臨時目錄等等將相關檔案匯出
    • -v /home/sakana/下載/test20200321:/root/test20200321

==== 在 container 內 ====

參考官方文件


產生伺服器和用戶端憑證及金鑰

因為容器裡面沒有裝 git 所以就先安裝 git

#zypper  install  -y  git

將 easy-rsa clone 下來

# git  clone  https://github.com/OpenVPN/easy-rsa.git

進入 easy-rsa 目錄

# cd   easy-rsa/easyrsa3

初始化新的 PKI 環境

# ./easyrsa  init-pki

init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /root/easy-rsa/easyrsa3/pki

建置新的憑證授權機構 (CA)
# ./easyrsa  build-ca  nopass

Using SSL: openssl OpenSSL 1.1.0i-fips  14 Aug 2018
Generating RSA private key, 2048 bit long modulus
........................................................................................+++++
..............................................+++++
e is 65537 (0x010001)
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:  可以輸入自訂名稱

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/root/easy-rsa/easyrsa3/pki/ca.crt

產生伺服器憑證和金鑰
# ./easyrsa  build-server-full  server  nopass

Using SSL: openssl OpenSSL 1.1.0i-fips  14 Aug 2018
Generating a 2048 bit RSA private key
.......................................................................+++++
.....+++++
writing new private key to '/root/easy-rsa/easyrsa3/pki/easy-rsa-237.niuWFO/tmp.z1xt2p'
-----
Using configuration from /root/easy-rsa/easyrsa3/pki/easy-rsa-237.niuWFO/tmp.7dpbOC
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'server'
Certificate is to be certified until Jun 21 13:11:46 2022 GMT (825 days)

Write out database with 1 new entries
Data Base Updated


產生用戶端憑證和金鑰

# ./easyrsa  build-client-full  client1.domain.tld  nopass

Using SSL: openssl OpenSSL 1.1.0i-fips  14 Aug 2018
Generating a 2048 bit RSA private key
.........................................................+++++
............................+++++
writing new private key to '/root/easy-rsa/easyrsa3/pki/easy-rsa-164.uQNueZ/tmp.oBHVMB'
-----
Using configuration from /root/easy-rsa/easyrsa3/pki/easy-rsa-164.uQNueZ/tmp.aWJmw3
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'client1.domain.tld'
Certificate is to be certified until Jun 21 13:07:36 2022 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

  • 務必儲存用戶端憑證和用戶端私有金鑰,因為您在設定用戶端時需要它們


將伺服器憑證和金鑰及用戶端憑證和金鑰複製到自訂資料夾,然後導覽到自訂資料夾
他的範例是 /custom_folder , 我是用自行掛載的資料夾

# cp  pki/ca.crt   /root/test20200321/

# cp  pki/issued/server.crt   /root/test20200321/

# cp  pki/private/server.key  /root/test20200321/

# cp  pki/issued/client1.domain.tld.crt  /root/test20200321/

# cp  pki/private/client1.domain.tld.key  /root/test20200321/

進入自訂資料夾
# cd   /root/test20200321/

等等需要把相關的檔案上傳到 ACM 上面, 所以上傳之前先來觀察該 Region 的 ACM 有沒有相關檔案 :) 目前是空的


將伺服器憑證和金鑰上傳到 ACM

# aws  acm  import-certificate --certificate file://server.crt --private-key file://server.key --certificate-chain  file://ca.crt --region us-east-2

{
    "CertificateArn": "arn:aws:acm:us-east-2:792117821604:certificate/2014cb32-1c3c-5412-c5d7-3b08ac91354f"
}

  • 這邊要注意的是 - 憑證和金鑰要上傳到用戶端 VPN 端點的同一區域, 我這邊以 us-east-2 為例


將用戶端憑證和金鑰上傳到 ACM

# aws  acm  import-certificate --certificate  file://client1.domain.tld.crt  --private-key file://client1.domain.tld.key --certificate-chain file://ca.crt --region us-east-2

{
    "CertificateArn": "arn:aws:acm:us-east-2:792117821604:certificate/32fc0d1d-6417-3a27-212c-7b25618a0583"
}

在該 Region 的 ACM 上面就會看到剛剛上傳的憑證





建立 用戶端 VPN 端點

接下來建立 AWS Client VPN

登入 AWS 主控台, 點選 Services -- > 點選  VPC 服務
在 VPC 主控台, 點選左方 Client VPN Endpoints


點選 Create Client VPN Endpoint

輸入名稱 / 敘述 / Client IPv4 CIDR


  • Client IPv4 CIDR 必須介於 /16 - /22 之間, 就是 Class B ~ 4 個 Class C 大小

選取 Server 憑證
勾選 Use mutual authentication -- > 選取 Client 憑證


  • 這邊可以觀察到 AWS Client VPN 有兩種驗證方式, 我們使用的是第二種
    • AD 驗證
    • 使用 Client 憑證進行交互驗證

Logging 的部分不啟用


在其他選項的部分
選取 VPC ID
DNS 的部分暫時沒有填寫, 因為要跟之後的 split-tunnel 一起進行實驗
Security Group ID 也暫時沒有選
VPN port 選取 1194 ( openVPN 預設的 port )
點選 Create Client VPN Endpoint



建立完成之後, 因為還沒有連接, 所以是 Pending-associate



將 Client VPN 與 VPC subnet 建立關聯

選取剛剛建立的 Client VPN
點選 Associations 分頁 -- > 點選 Associate

選取要關聯的 VPC 以及 Subnet
點選 Associate



經過一段時間觀察, 就會發現 Client VPN state 變成 Available



授權用戶端存取網路

選取剛剛建立的 Client VPN
點選 Authorization 分頁 -- > 點選 Authorize Ingress


Destination network to enable: 輸入 0.0.0.0/0 ( 任何 ) 
輸入 Description
點選 Add authorization rule



新增 Security Group for openVPN 連線

登入 AWS 主控台, 點選 Services -- > 點選  VPC 服務
在 VPC 主控台, 點選左方 Security Groups
點選 Create security group
輸入 名稱 / 敘述 / 選取 VPN
點選 Create

選取剛剛建立 openvpn-udp 的 security group
點選 Inbound Rules 分頁 -- > 點選 Edit rules


點選 Add Rule
選取 Custom UDP Rule
Port Range 輸入 1194
Source 填入 0.0.0.0/0
點選 Save rules 


建立完成

接下來我們要讓剛剛建立的 Client VPN 加入這筆 Security Group
點選左方的 Client VPN Endpoints

選取剛剛建立的 Client VPN
點選 Security Groups 分頁 -- > 點選 Apply Security Groups
點選剛剛建立 openvpn-udp 的 security grouip id
點選 Apply Security Groups 


  • 這邊實驗的關係, 我套用剛剛建立的 openvpn-udp 與 VPN default 規則




下載 用戶端 VPN 端點組態檔案

==== 在主機上面 ====

這邊我們就回到主機上面了, 等等可能要安裝 openVPN 的軟體以及設定

選取剛剛建立的 Client VPN
點選 Download Client Configuration


點選 Download 下載 設定檔

  • 剛剛在上面有建議可以將 container 掛載主機的特定目錄, 所以我是將設定檔放在同一個目錄 test20200321

進入特定的目錄, 以我來說, 我是將 ~/下載/test20200321 目錄與剛剛 container 共同掛載

>  cd   ~/下載/test20200321

觀察相關資訊

> ls

20200321.xml  ca.crt client1.domain.tld.crt  client1.domain.tld.key  downloaded-client-config.ovpn  server.crt  server.key

  • 這邊可以看到剛剛下載的 downloaded-client-config.ovpn 以及剛剛建立的憑證
  • 也可以看到 client 的憑證與 key


編輯 downloaded-clietn-config.ovpn

> vi  downloaded-client-config.ovpn


  • 在 remote 設定的部分, 加上任一主機名稱
    • remote test.cvpn-endpoint-002c11553b655b02c.prod.clientvpn.us-east-2.amazonaws.com 1194
  • 原因是 Client VPN 的 DNS name 是 *.cvpn-endpoint-002c11553b655b02c.prod.clientvpn.us-east-2.amazonaws.com 
    • 如果只是 cvpn-endpoint-002c11553b655b02c.prod.clientvpn.us-east-2.amazonaws.com 會解析不到

  • 在 </ca> 後面加入 cert 以及 key 兩個區段
    • cert 加入 client1.domain.tld.crt 檔案憑證內容
    • key 加入 client1.domain.tld.key 檔案 key 內容





在 openSUSE Leap 15.1 的 Network Manager 連線 openVPN

點選桌面右上角的按鈕 -- > 點選 設定值按鈕
點選左邊的網路
點選 VPN 右邊的 + 按鈕


點選 從檔案匯入 


選取剛剛的 downloaded-clietn-config.ovpn -- > 開啟

點選 加入


  • 這邊注意一下 閘道是否是 test.cvpn-endpoint-xxxxxxx

輸入管理者密碼來改變網路

由於 openVPN 是走 UDP port 1194, 所以本機的 firewall 也要開啟

#yast2  firewall

點選 左邊的 public Zone
點選 openvpn -- > 點選 Add
點選 Accept

完成 firewall 設定

連接 VPN 之前來觀察一下資訊

# ip  route  show

default via 192.168.0.1 dev wlan0 proto dhcp metric 600 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
192.168.0.0/24 dev wlan0 proto kernel scope link src 192.168.0.232 metric 600 

ping 我在 AWS 主機 172.31.14.128 -- > 失敗


接下來啟動 VPN
點選開關啟動



# ip route show

default via 10.23.0.1 dev tun0 proto static metric 50 
default via 192.168.0.1 dev wlan0 proto dhcp metric 600 
3.12.63.134 via 192.168.0.1 dev wlan0 proto static metric 600 
10.23.0.0/27 dev tun0 proto kernel scope link src 10.23.0.2 metric 50 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
192.168.0.0/24 dev wlan0 proto kernel scope link src 192.168.0.232 metric 600 
192.168.0.1 dev wlan0 proto static scope link metric 600 

ping 我在 AWS 主機 172.31.14.128 -- > 成功
ping  www.hinet.net -- > 失敗

  • 因為現在預設路由是走 VPN 出去, 我們並沒有設定 Split tunnel / DNS / 路由

另外 VPN 的設定, 個人會習慣把 自動連線取消勾選



到這邊, 如果只是要連線 AWS 的 內部 Subnet, 應該就達成了
但是如果想要
  • 可以連線 AWS Subnet
  • 也可以上網呢?

接下來就透過 Split tunnel 來達成

分割通道 ( split tunnel )
  • 啟用的時候讓 VPN 可以同時用自己的網路對外, 以及連 AWS VPC
    • 如果沒有啟用, 因為都是透過 AWS Client VPN 所以沒辦法上網

還沒有啟用 split tunnel 的時候來觀察 pint www.hinet.net 資訊

# ping www.hinet.net

PING hinet-hp.cdn.hinet.net (61.221.230.163) 56(84) bytes of data.
64 bytes from 61-221-230-163.HINET-IP.hinet.net (61.221.230.163): icmp_seq=1 ttl=50 time=196 ms
64 bytes from 61-221-230-163.HINET-IP.hinet.net (61.221.230.163): icmp_seq=2 ttl=50 time=100 ms

回到 Client VPN 設定
選取剛剛建立的 Client VPN
點選 Actions -- > Modify Client VPN Endpoint 



勾選 Enable DNS Server -- > 輸入 DNS Server IP
勾選 Enable split-tunnel
點選 Modify Client VPN Endpoint



接下來建立路由

點選 Route Table 分頁 -- > 點選 Create Route


輸入 Route destination, 這邊我給 0.0.0.0/0
選取 VPC Subnet ID
點選 Create Route


再次啟用 VPN


# ip route show

default via 10.23.0.129 dev tun0 proto static metric 50 
default via 192.168.0.1 dev wlan0 proto dhcp metric 600 
3.12.63.134 via 192.168.0.1 dev wlan0 proto static metric 600 
10.23.0.128/27 dev tun0 proto kernel scope link src 10.23.0.130 metric 50 
18.219.170.100 via 192.168.0.1 dev wlan0 proto static metric 600 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
172.31.0.0/16 via 10.23.0.129 dev tun0 proto static metric 50 
192.168.0.0/24 dev wlan0 proto kernel scope link src 192.168.0.232 metric 600 
192.168.0.1 dev wlan0 proto static scope link metric 600 

  • 這邊有觀察到 default route 有不同

ping 我在 AWS 主機 172.31.14.128 -- > 成功
ping  www.hinet.net -- > 成功

# ping www.hinet.net

PING hinet-hp.cdn.hinet.net (61.221.230.165) 56(84) bytes of data.
64 bytes from 61-221-230-165.HINET-IP.hinet.net (61.221.230.165): icmp_seq=1 ttl=33 time=610 ms
64 bytes from 61-221-230-165.HINET-IP.hinet.net (61.221.230.165): icmp_seq=2 ttl=33 time=628 ms



用 traceroute 觀察

# traceroute www.hinet.net

traceroute to www.hinet.net (61.221.230.165), 30 hops max, 60 byte packets
 1  * * *
 2  ec2-52-15-0-31.us-east-2.compute.amazonaws.com (52.15.0.31)  486.571 ms 486.564 ms ec2-52-15-0-35.us-east-2.compute.amazonaws.com (52.15.0.35)  486.501 ms
 3  100.65.26.160 (100.65.26.160)  486.391 ms 100.65.27.128 (100.65.27.128)  486.386 ms 100.65.27.32 (100.65.27.32) 486.382 ms
 4  100.66.12.60 (100.66.12.60)  486.304 ms 100.66.12.180 (100.66.12.180)  486.303 ms 100.66.12.38 (100.66.12.38) 486.214 ms
 5  100.66.15.162 (100.66.15.162)  486.330 ms 100.66.14.14 (100.66.14.14)  486.339 ms 100.66.14.134 (100.66.14.134)  486.279 ms
 6  100.66.6.229 (100.66.6.229)  486.247 ms 100.66.6.9 (100.66.6.9)  320.587 ms 100.66.7.235 (100.66.7.235)  320.967 ms

  • 這邊就可以觀察到是從 AWS 出去的


好吧, 想實驗的東西又完成一件, 離 AWS 又進了一步

~ enjoy it



Reference:

nginx 使用 SSL 憑證 with openSUSE Leap 15.1 in Azure 小記

nginx 使用 SSL 憑證 with openSUSE Leap 15.1 in Azure 小記

OS: openSUSE Leap 15.1 in Azure

今天來嘗試讓 nginx 使用 https 方式連線
要使用 https 方式連線首先要有憑證, 那就來申請憑證吧 :)

申請 SSL 憑證

我是用  https://www.sslforfree.com/ 這個網站來取得
  • 他也是利用 Let's Encrypt 來讓使用者取得憑證

輸入自己管理的網域 -- > Create Free SSL Certificate


選取驗證的方式, 我是使用 DNS 的方式, 點選 Manual Verification(DNS)


DNS 驗證的方式就是藉由新增 TXT 記錄來進行驗證 
-- > 點選 Manually Verify Domain

我 DNS 代管是使用 Gandi.net

按照上面的要求在 DNS 代管的網站新增兩筆 TXT Record


  • 如果要確認是否設定完成, 可以使用 host 指令
    • #host  -t txt  _acme-challenge.YOUR_DOMAIN

DNS 紀錄設定好之後

可以點選 Verify 的兩個連結觀察
  • Gandi 最小 TTL 值是 300 秒, 雖然他要求 1 秒的 TTL, 不過只要等 300 秒, 還是可以檢查 Value, 所以不影響

點選 Download SSL Certificate


如果剛剛的 DNS TXT 紀錄都有設定正確
就會出現 Certificate Successfully Generated 頁面
上面是說 SSL 憑證 90 天之後過期, 可以註冊帳號集中管理或是提醒到期, 這個部分就看個人

畫面中央有 Certificate Files
有相關檔案, 點選 Download All SSL Certificate Files 來下載 SSL 憑證檔案

這個時候會下載一個 sslforfree.zip 的檔案, 裡面包含 3 個檔案
  • ca_bundle.crt - 中繼憑證
  • certificate.crt - 公鑰
  • private.key - 私鑰

SSL 憑證格式的資訊如果想要進一步了解, 可以參考保哥的文章

接下來可以參考網站提供的安裝文件 https://www.sslforfree.com/#tutorials


這邊就根據自己的平臺以及伺服器來選擇

我使用 nginx
為了管理方便我在 /etc/nginx 目錄下建立一個 ssl  目錄

# mkdir  /etc/nginx/ssl

將上面的 3 個檔案上傳到 伺服器上面 /etc/nginx/ssl 目錄下
  • ca_bundle.crt - 中繼憑證
  • certificate.crt - 公鑰
  • private.key - 私鑰

將 公鑰與中繼憑證合併

# cat   /etc/nginx/ssl/certificate.crt  > /etc/nginx/ssl/your_domain.crt
# printf  "\n"  >>  /etc/nginx/ssl/your_domain.crt 
# cat   /etc/nginx/ssl/ca_bundle.crt  >>  /etc/nginx/ssl/your_domain.crt

  • 這邊注意第一個指令是用 > 輸出導向, 然後後面是用 >>  附加的方式
  • certificate.crt 以及 ca_bundle.crt 順序要注意 

修改 nginx 設定檔
# vim  /etc/nginx/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
    use epoll;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    include conf.d/*.conf;
    server {
        listen       80;
        listen       443 ssl;
        server_name  YOUR_DOMAIN;
        ssl_certificate      /etc/nginx/ssl/your_domin.crt;
        ssl_certificate_key  /etc/nginx/ssl/private.key;
        location / {
            root   /srv/www/htdocs/;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /srv/www/htdocs/;
        }
    }
    
    include vhosts.d/*.conf;
}

  • 加入上面紅色部分

將 nginx 服務 reload

# systemctl   reload   nginx

因為是走 HTTPS, 所以記得要開 port 443 

在 Azure 該 VM 的網路設定內, 點選 新增輸入連接埠規則,設定 port 443 可以連線

開啟瀏覽器, 輸入 https://YOUR_DOMAIN
就可以看到可愛的鎖頭符號了


又往 nginx 前進一步了 :)

~ enjoy it


Reference:

Saturday

7 March, 2020

使用 curl 測試 CDN 小記

使用 curl 測試 CDN 小記

OS: openSUSE Leap 15.1
Curl: 7.60.0

因為公司也有 CDN 的服務, 所以就來 study 一下如何測試 CDN

找了網路上的文章來進行實驗

> curl  -I  img1.momoshop.com.tw

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 206
Connection: keep-alive
Date: Thu, 13 Feb 2020 06:37:14 GMT
Last-Modified: Wed, 04 Sep 2019 08:33:23 GMT
ETag: "5d6f76d3-ce"
Expires: Fri, 12 Feb 2021 06:37:14 GMT
Cache-Control: max-age=31536000
X-Image-Server: a1-imgweb62
X-Cache-Server: a1-rproxy64
X-Cache-Status: HIT
Cache-Control: public
Accept-Ranges: bytes
X-Cache: Hit from cloudfront
Via: 1.1 ff0896bca963fdb839934a38daad05c9.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: TPE50-C1
X-Amz-Cf-Id: s_DGUUBq7VKqDZprbRdA75kJeG5So0PLUwMRyWjqwA4TxjSefOmfEg==
Age: 1923399


  • -I, --head (HTTP  FTP FILE) Fetch the  headers only! 顯示 Headers
  • Cache-Control:
  • X-Cache: 是否在 CDN 有快取
    • HIT: 在 CDN 上有快取
    • MISS: 在 CDN 上面沒有快取, 會跟原站抓
  • X-Amz-Cf-Pop: 這個欄位是快取的站, 這邊可以觀察是 Taipei 的 Pop 點
    • 但是不同的供應商, 會有不同的欄位, Cloudflare 可能就是 CF-RAY: 56fc8a38f94545d0-TPE
  • ETag:

  • Expires: 過期時間
    • 瀏覽器收到這個 Response 之後就會把這個資源給快取起來,當下一次使用者再度造訪這個頁面或是要求這個圖片的資源的時候,瀏覽器會檢視「現在的時間」是否有超過這個 Expires。如果沒有超過的話,那瀏覽器「不會發送任何 Request」,而是直接從電腦裡面已經存好的 Cache 拿資料。

  • RFC2616 規範 max-age 會蓋掉 Expires, 所以實際上用到的是 Cache-Control: max-age



剛剛是針對某個網站
哪如果是針對 CDN 可能快取的物件呢? 

> curl -I  https://img1.momoshop.com.tw/goodsimg/0006/750/353/6750353_L.jpg?t=1581517754

HTTP/2 200 
content-type: image/jpeg
content-length: 22654
date: Fri, 06 Mar 2020 13:40:47 GMT
last-modified: Wed, 28 Aug 2019 15:00:03 GMT
etag: "5d6696f3-587e"
expires: Sat, 06 Mar 2021 13:40:47 GMT
cache-control: max-age=31536000
x-image-server: b1-imgweb61
access-control-allow-origin: *
access-control-max-age: 1000
access-control-allow-methods: POST, GET, OPTIONS, DELETE, PUT
access-control-allow-headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token
x-cache-server: a1-rproxy65
x-cache-status: HIT
cache-control: public
accept-ranges: bytes
x-cache: Miss from cloudfront
via: 1.1 5c4e99b05f9fd6102a3e039a6bd98968.cloudfront.net (CloudFront)
x-amz-cf-pop: TPE50-C1
x-amz-cf-id: JrqvYZNlLjV5zHS323SyuQ8pqzJgciSDOW4sEl1kl1Wj6ky_D4jWjg==

上面有提到過的就不重提
  • X-cache: Miss from cloudfront ( Cloudfront 上面沒有快取 ), 所以 CDN 會跟原站抓
    • 這邊也可以觀察到沒有 age 的 header, 也就是說沒有物件在 CDN 上已經快取的時間
  • 也可以去觀察 x-cache-server 以及 x-image-server 資訊
  • last-modified:
    • 會跟 If-Modified-Since 搭配使用, 如果超過時間但是沒有變動, 還是會從快取出

很短的時間重新抓一次

> curl -I https://img1.momoshop.com.tw/goodsimg/0006/750/353/6750353_L.jpg?t=1581517754

HTTP/2 200 
content-type: image/jpeg
content-length: 22654
date: Fri, 06 Mar 2020 13:40:47 GMT
last-modified: Wed, 28 Aug 2019 15:00:03 GMT
etag: "5d6696f3-587e"
expires: Sat, 06 Mar 2021 13:40:47 GMT
cache-control: max-age=31536000
x-image-server: b1-imgweb61
access-control-allow-origin: *
access-control-max-age: 1000
access-control-allow-methods: POST, GET, OPTIONS, DELETE, PUT
access-control-allow-headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token
x-cache-server: a1-rproxy65
x-cache-status: HIT
cache-control: public
accept-ranges: bytes
x-cache: Hit from cloudfront
via: 1.1 41d05f95698dc73a0a8a2f90b9eb739a.cloudfront.net (CloudFront)
x-amz-cf-pop: TPE50-C1
x-amz-cf-id: YL_Ii4eNQTB0VfTIlpSo77A8cHB4aOk7Mv_K4dhix_OqBhbW6tkqHw==
age: 28

  • 這邊可以觀察到 CloudFront 已經有資料, 然後也有 age 的資料

接下來進行另外一個測試 就是 支援 TLS 的版本
現在 TLS 版本的支援, 很多瀏覽器都會要求到一定的 TLS 版本, 目前 大概都要支援到 TLS 1.2 以上的版本

> curl  -I  -v  --tlsv1.0  https://img1.momoshop.com.tw

* Rebuilt URL to: https://img1.momoshop.com.tw/
*   Trying 13.35.153.7...
* TCP_NODELAY set
* Connected to img1.momoshop.com.tw (13.35.153.7) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* TLSv1.0 (OUT), TLS handshake, Client hello (1):
* TLSv1.0 (IN), TLS alert, Server hello (2):
* error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
* stopped the pause stream!
* Closing connection 0
curl: (35) error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version

  • 這邊使用 -v 來顯示詳細資訊
  • --tlsv1.0 指定使用 TLS 1.0 協定
  • 這邊可以觀察到 使用 TLS 1.0 是被拒絕的

接下來嘗試 TLS 1.1 and TLS 1.2

> curl  -I  -v --tlsv1.1  https://img1.momoshop.com.tw

* Rebuilt URL to: https://img1.momoshop.com.tw/
*   Trying 13.35.153.65...
* TCP_NODELAY set
* Connected to img1.momoshop.com.tw (13.35.153.65) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* TLSv1.1 (OUT), TLS handshake, Client hello (1):
* TLSv1.1 (IN), TLS handshake, Server hello (2):
* TLSv1.1 (IN), TLS handshake, Certificate (11):
* TLSv1.1 (IN), TLS handshake, Server key exchange (12):
* TLSv1.1 (IN), TLS handshake, Server finished (14):
* TLSv1.1 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.1 (OUT), TLS change cipher, Client hello (1):
* TLSv1.1 (OUT), TLS handshake, Finished (20):
* TLSv1.1 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.1 / ECDHE-RSA-AES128-SHA
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=*.momoshop.com.tw
*  start date: Jun  3 00:00:00 2019 GMT
*  expire date: Jul  3 12:00:00 2020 GMT
*  subjectAltName: host "img1.momoshop.com.tw" matched cert's "*.momoshop.com.tw"
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x564c5fcb9040)
> HEAD / HTTP/2
> Host: img1.momoshop.com.tw
> User-Agent: curl/7.60.0
> Accept: */*
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200 
HTTP/2 200 

> curl -I -v --tlsv1.2 https://img1.momoshop.com.tw

* Rebuilt URL to: https://img1.momoshop.com.tw/
*   Trying 13.35.153.7...
* TCP_NODELAY set
* Connected to img1.momoshop.com.tw (13.35.153.7) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=*.momoshop.com.tw
*  start date: Jun  3 00:00:00 2019 GMT
*  expire date: Jul  3 12:00:00 2020 GMT
*  subjectAltName: host "img1.momoshop.com.tw" matched cert's "*.momoshop.com.tw"
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x56535129a040)
> HEAD / HTTP/2
> Host: img1.momoshop.com.tw
> User-Agent: curl/7.60.0
> Accept: */*
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200 
HTTP/2 200 

  • 其實如果沒有特別指定, 會用比較高的版本去連接
  • 這邊可以觀察 TLS 1.1 and TLS 1.2 都支援

同場加映:
然後也可以用另外一個指令來檢查 TLS, 就是 sslscan 指令

> sslscan  https://img1.momoshop.com.tw

Version: 1.11.10
OpenSSL 1.0.2p-fips  14 Aug 2018

OpenSSL version does not support SSLv2
SSLv2 ciphers will not be detected

OpenSSL version does not support SSLv3
SSLv3 ciphers will not be detected
Testing SSL server img1.momoshop.com.tw on port 443 using SNI name img1.momoshop.com.tw

  TLS Fallback SCSV:
Server does not support TLS Fallback SCSV

  TLS renegotiation:
Session renegotiation not supported

  TLS Compression:
Compression disabled

  Heartbleed:
TLS 1.2 not vulnerable to heartbleed
TLS 1.1 not vulnerable to heartbleed
TLS 1.0 not vulnerable to heartbleed

  Supported Server Cipher(s):
Preferred TLSv1.2  128 bits ECDHE-RSA-AES128-GCM-SHA256   Curve P-256 DHE 256
Accepted  TLSv1.2 128 bits  ECDHE-RSA-AES128-SHA256       Curve P-256 DHE 256
Accepted  TLSv1.2 128 bits  ECDHE-RSA-AES128-SHA          Curve P-256 DHE 256
Accepted  TLSv1.2 256 bits  ECDHE-RSA-AES256-GCM-SHA384   Curve P-256 DHE 256
Accepted  TLSv1.2 256 bits  ECDHE-RSA-AES256-SHA384       Curve P-256 DHE 256
Accepted  TLSv1.2 256 bits  ECDHE-RSA-AES256-SHA          Curve P-256 DHE 256
Accepted  TLSv1.2 128 bits  AES128-GCM-SHA256            
Accepted  TLSv1.2 256 bits  AES256-GCM-SHA384            
Accepted  TLSv1.2 128 bits  AES128-SHA256                
Accepted  TLSv1.2 256 bits  AES256-SHA                   
Accepted  TLSv1.2 128 bits  AES128-SHA                   
Preferred TLSv1.1  128 bits ECDHE-RSA-AES128-SHA          Curve P-256 DHE 256
Accepted  TLSv1.1 256 bits  ECDHE-RSA-AES256-SHA          Curve P-256 DHE 256
Accepted  TLSv1.1 256 bits  AES256-SHA                   
Accepted  TLSv1.1 128 bits  AES128-SHA                   

  SSL Certificate:
Signature Algorithm: sha256WithRSAEncryption
RSA Key Strength:    2048

Subject:  *.momoshop.com.tw
Altnames: DNS:*.momoshop.com.tw
Issuer:   Amazon

Not valid before: Jun  3 00:00:00 2019 GMT
Not valid after:  Jul 3 12:00:00 2020 GMT

然後也常常看到網路上的人使用下列的選項
> curl  -ksvo  /dev/null  https://img1.momoshop.com.tw

  • -k, --insecure
  • -s, --silent, Silent or quiet mode. Don't show progress meter or error messages.
  • -v, --verbose
  •  -o, --output <file>

整理一下今天學習到的知識重點

也許可以利用 curl -I 的方式來看 Header 來觀察是否有 CDN, 也許 Header 不一樣

> curl -I  https://media.etmall.com.tw

HTTP/2 403 
server: HiNetCDN/1908
date: Sat, 07 Mar 2020 15:00:16 GMT
content-type: text/html
content-length: 1147
vary: Accept-Encoding
x-cache: MISS, MISS, MISS
x-request-id: 08a83a10d0e14edecab443f4bde4c753

> curl  -I  http://cf.shopee.tw

HTTP/1.1 404 Not Found
Server: NWS_Oversea_AP
Connection: keep-alive
Date: Sat, 07 Mar 2020 15:00:36 GMT
Last-Modified: Sat, 07 Mar 2020 15:00:00 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 19
X-Content-Type-Options: nosniff
X-Daa-Tunnel: hop_count=2
X-NWS-LOG-UUID: 5423788696303268195 b38e6f5a9afc4fde3c81e984a88d9c0f
Access-Control-Allow-Origin: *
X-CDN: tencent
X-Cache-Lookup: Hit From Upstream

可以藉由觀察 Cache-Control 來觀察是否快取
  • public
    • 可以由任何快取給存取
  • private
    • 快取只給一個使用者使用,且不能被共用的快取伺服器給儲存過。隱私視窗(無痕模式)的快取就可能是這樣子。
  • no-cache
    • 快取伺服器在把已儲存的複製版本傳給請求者之前,先會送一個請求給網頁伺服器做驗證
  • no-store
    • 快取不該存取任何的使用者請求或者伺服器的回覆。每個請求都是送到原始的伺服器去取得資源。

期限的部分一般則是可以看 Cache-Control 的 max-age 來決定
會使用 etag 或是 last-modified 來進行快取內容驗證

再度前進一小步 :)

~ enjoy it


Reference:


nginx with openSUSE Leap 15.1 in Azure 小記 Part 2

nginx with openSUSE Leap 15.1 in Azure 小記 Part 2

OS: openSUSE Leap 15.1 in Azure
Nginx: 1.14.2

上次練習 nginx 靜態網頁以及 proxy, 今天來實驗 HTTP Load Balancing

架構想法如下


實驗環境
OS: openSUSE Leap 15.1 in Azure x 3 VM
  • 前面有 1 台 openSUSE Leap 15.1 執行 nginx 
  • 後面有 2 台 openSUSE Leap 15.1 使用 container 執行 Web 服務

參考上次的文章

首先建立 2 台 openSUSE Leap 15.1 in Azure, 執行以下動作
  • 啟動 docker 服務
    • # systemctl  start docker
  • 執行 container 然後 port 開在 80
    • # docker  run -d -p  80:80 russmckendrick/cluster
  • Azure 該 VM 的網路設定內, 設定 port 80 可以連線
  • 設定該 VM DNS 名稱
  • 確認都可以進行存取





建立 1 台 openSUSE Leap 15.1 in Azure, 執行以下動作
  • 使用 zypper 指令 安裝 nginx
    • # zypper  install  nginx
  • 啟動 nginx 服務
    • # systemctl start nginx
    • # systemctl  enable  nginx
  • 設定 DNS 名稱

上面的動作前一篇文章就已經有了, 所以不贅述

接下來進行 HTTP Load Balancing 實驗

修改 nginx 設定檔

# vi   /etc/nginx/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
    use epoll;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    include conf.d/*.conf;
    upstream backend {
            server test2020022801.eastus.cloudapp.azure.com;
            server test2020022802.eastus.cloudapp.azure.com;
    }
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   /srv/www/htdocs/;
            index  index.html index.htm;
            proxy_pass http://backend;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /srv/www/htdocs/;
        }
    }
    
    include vhosts.d/*.conf;
}

  • 新增 upstream backend 區段, 指向剛剛建立的 2 台 Web 服務
  • 新增 proxy_pass 指向 http://backend

善用 #nginx -t 檢查語法
  • 一開始是寫獨立的 http 區段, 結果就被警告 http 重複設定

將服務 reload 

# systemctl  reload  nginx

進行測試
在瀏覽器開啟 http://testnginx.eastus.cloudapp.azure.com


  • 確認會導向後端不同的 Web 服務

Load Balancing 的方式有 6 種
  • Nginx open source 支援其中4種, nginx plus 支援 6 種
    • Round Robin ( 預設 )
    • Least Connections
    • IP Hash
    • Generic Hash
    • Least Time ( NGINX Plus only )
    • Random

接下來多實驗一個設定 Server Weight

剛剛有提到, 預設使用 Round Robin 方式將連線平均的分配到後端的服務
那如果 VM 他的規格大小不一樣, 或是想要測試金絲雀佈署這樣的改版測試呢?

這個時候考慮使用 Server Weight 權重方式來因應

修改 nginx 設定檔

# vi   /etc/nginx/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
    use epoll;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    include conf.d/*.conf;
    upstream backend {
           server test2020022801.eastus.cloudapp.azure.com weight=3;
           server test2020022802.eastus.cloudapp.azure.com;
    }
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   /srv/www/htdocs/;
            index  index.html index.htm;
            proxy_pass http://backend;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /srv/www/htdocs/;
        }
    }
    
    include vhosts.d/*.conf;
}

  • 針對剛剛後端服務其中一台設定 weight=3
    • 沒有設定的話, 權重設定預設是 1, 目前有 2 台機器服務, 所以總共是 3 + 1 = 4, 也就是說 test2020022801 被存取的次數就會佔 3/4 ( 75% ), 另外一台是 1/4 ( 25% )

將服務 reload 

# systemctl  reload  nginx

進行測試
在瀏覽器開啟 http://testnginx.eastus.cloudapp.azure.com

  • 觀察 2 台機器服務的顯示比例

這樣算是朝向 nginx 的一小步  :)

~ enjoy it


Reference

Sunday

23 February, 2020

nginx with openSUSE Leap 15.1 in Azure 小記

nginx with openSUSE Leap 15.1 in Azure 小記


OS: openSUSE Leap 15.1 in Azure
Nginx: 1.14.2


之前 web 服務都是使用 Apache 比較多, 但是最近覺得要會 nginx 才能符合之後的需求, 所以開始來練習 nginx :) 今天主要練習
  • Nginx 作爲靜態網頁
  • Nginx 作為 Proxy Server


Nginx


使用環境 openSUSE Leap 15.1 in Azure
  • 已經登入到 Azure Portal 並建立一台 openSUSE Leap 15.1
  • 使用 ssh 連線在 Azure 上面的 openSUSE Leap 15.1


先來使用 zypper 指令 安裝 nginx 


# zypper  install  nginx


Loading repository data...
Reading installed packages...
Resolving package dependencies...


The following 9 NEW packages are going to be installed:
  libXpm4 libgd3 libjbig2 libjpeg8 libtiff5 libwebp6 libxslt1 nginx vim-plugin-nginx


The following recommended package was automatically selected:
  vim-plugin-nginx


9 new packages to install.
Overall download size: 1.7 MiB. Already cached: 0 B. After the operation, additional 4.8 MiB will be used.
Continue? [y/n/v/...? shows all options] (y):  Y


觀察服務狀態


# systemctl status nginx


● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: inactive (dead)


啟動 nginx 服務


# systemctl start nginx


觀察相關資訊


# systemctl status nginx


● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: active (running) since Thu 2020-02-20 13:00:00 UTC; 1s ago


確認開機是否會自動啟動


# systemctl  is-enabled  nginx
disabled


設定開啟自動啟動


# systemctl  enable  nginx


Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.


再次觀察
# systemctl  is-enabled  nginx
enabled


這樣 nginx 就已啟動然後開機後也會自動啟動


Lab 1: 測試靜態網頁


觀察 listen port
  • 早期是用 netstat 指令, 現在是用 ss 指令了


# ss  -tupln


Netid State      Recv-Q Send-Q                                 Local Address:Port                     Peer Address:Port              
udp   UNCONN     0 0                                         0.0.0.0%eth0:68                       0.0.0.0:* users:(("wickedd-dhcp4",pid=685,fd=9))
tcp   LISTEN     0 128                                             0.0.0.0:80             0.0.0.0:* users:(("nginx",pid=120751,fd=6),("nginx",pid=120750,fd=6))
tcp   LISTEN     0 128                                             0.0.0.0:22             0.0.0.0:* users:(("sshd",pid=1189,fd=3))
tcp   LISTEN     0 128                                                 [::]:22           [::]:* users:(("sshd",pid=1189,fd=4))


有觀察到 port 80 listen, 但是這個是本機的狀況, 要可以對外連線, 還要在 Azure 上面設定 Security Group 讓 網路流量可以通過


在 Azure 該 VM 的網路設定內, 點選 新增輸入連接埠規則,設定 port 80 可以連線




接下來測試網頁狀況


在瀏覽器開啟 http://YOUR_SERVER_IP


  • 這個時候會得到 403 Forbidden, 


觀察 error.log
# cat  /var/log/nginx/error.log


2020/02/20 13:01:32 [error] 120751#120751: *1 directory index of "/srv/www/htdocs/" is forbidden,


藉由 nginx -t 來觀察設定檔位置以及有沒有問題


# nginx  -t


nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful


  • 從這邊可以得知設定檔在 /etc/nginx/nginx.conf


觀察一下目前的設定檔


# egrep  -v  '^$|^#|#'  /etc/nginx/nginx.conf 


worker_processes  1;
events {
    worker_connections  1024;
    use epoll;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    include conf.d/*.conf;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   /srv/www/htdocs/;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /srv/www/htdocs/;
        }
    }
    
    include vhosts.d/*.conf;
}


整理一下
  • 網站的根目錄應該是在 /srv/www/htdocs
  • 首頁的檔案應該是 index.html 或是 index.htm
  • 觀察  /etc/nginx/conf.d/ 目錄下     - 沒有檔案
  • 觀察  /etc/nginx/vhosts.d/ 目錄下 - 沒有檔案


觀察一下資訊
# ls  /srv/www/htdocs/
50x.html


該目錄中, 並沒有 index.html 或是 index.htm,  所以就會 Forbidden


嘗試建立 /srv/www/htdocs/index.html
# vim  /srv/www/htdocs/index.html


<html> This is lab site </html>


測試是否生效
在瀏覽器開啟 http://YOUR_SERVER_IP




到這邊的話, 基本的靜態網頁測試就應該可以了

Lab 2:  測試 Proxy Server 的用法


為了要有測試的感覺, 先把 docker 服務啟動


# systemctl  start  docker


觀察服務狀態


# systemctl  status  docker


● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor pre>
   Active: active (running) since Sat 2020-02-22 04:12:17 UTC; 5min ago


執行 container 然後 port 開在 8080 
# docker  run  -d  -p  8080:80  russmckendrick/cluster


在 Azure 該 VM 的網路設定內, 設定 port 8080 可以連線






測試是否生效
在瀏覽器開啟 http://YOUR_SERVER_IP:8080




應該會看到網頁以及該 container 的 id


從這邊我們可以觀察到這個服務是正常的


接下來要進行 Proxy Server 的測試
測試想法
  • 當使用者連線到某個網域名稱( FQDN ), 就會轉到 本機 port 8080


將剛剛 Azure 上面的安全性規則, 允許 port 8080 刪除




再次嘗試存取剛剛的網站 觀察相關資訊
在瀏覽器開啟 http://YOUR_SERVER_IP:8080


這個時候其實會發現無法存取 ( 因為安全性規則 firewall 已經被刪除)


開始進行實作
在 Azure 上面替 openSUSE Leap 15.1 設定 DNS 名稱


在 VM 的概觀頁面上面可以看到有 DNS 設定的按鈕
點選 設定
  • 這個動作其實是會進入該公用 IP 的組態內




輸入 DNS 名稱




點選儲存
這個時候這個 VM 就會將這個名稱綁定公用 IP


修改 nginx 設定檔


# vim   /etc/nginx/nginx.conf


worker_processes  1;
events {
    worker_connections  1024;
    use epoll;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    include conf.d/*.conf;
    server {
       server_name test20200222.eastus.cloudapp.azure.com;
       location / {
       proxy_pass http://127.0.0.1:8080;
       }
    }
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   /srv/www/htdocs/;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /srv/www/htdocs/;
        }
    }
    
    include vhosts.d/*.conf;
}


  • 在  http 區段內新增一個 server 區段
  • server_name 指定剛剛綁定的 FQDN
  • Proxy_pass 指向 port 8080


這邊要善用  nginx -t 來檢查相關設定


進行測試
在瀏覽器開啟 http://test20200222.eastus.cloudapp.azure.com
這個時候會看到剛剛啟動的網頁
Proxy Server 功能測試完畢


整理資訊
  • 設定檔 /etc/nginx/nginx.conf
    • 相關目錄 /etc/nginx
  • Log 目錄 : /var/log/nginx


這樣算是朝向 nginx 的一小步  :)


~ enjoy it


Reference

Saturday

11 January, 2020

使用 Google Stackdriver Monitoring API Python Samples 監控 過去一週 CPU 小於 20% VM小記

20191229

使用 Google Stackdriver Monitoring API Python Samples 監控 過去一週 CPU 小於 20% VM小記

OS: container with openSUSE Leap 15.1

今天要來嘗試使用 Stackdriver monitor API 透過 python 列出過去一週 CPU 小於 20 % 的 VM

環境使用之前建立好的 openSUSE Leap 15.1, 上面已經安裝好雲端的工具

==== 在主機上面 ====

啟動 container

> docker  run  -v  ~/.aws:/root/.aws -v  ~/.azure:/root/.azure  -v ~/.config/gcloud:/root/.config/gcloud  -v  ~/.ssh:/root/.ssh  -it  sakana/ansible_opensuse151  /bin/bash

==== 在 container 內 ====

在這邊使用服務帳戶的方式來處理, 所以要先建立服務帳戶

建立的方式有 2 種

==== 1. GCP Console 方式 ====

登入 GCP console

點選 導覽選單 -- > IAM 與管理 -- > 服務帳戶 

點選 建立服務帳戶


輸入帳戶名稱 -- > 建立

角色的部分選取 監控/Monitoring 管理員  -- > 繼續


點選 建立金鑰

選取金鑰類型, 這邊我選 JSON  -- > 建立


下載金鑰到本機

點選 完成
完成服務帳號建立以及金鑰建立

==== 2. 指令方式 ====

參考官方網頁

建立服務帳戶

# gcloud iam service-accounts create test20200111 --project  YOUR_PROJECT_ID

  • test20200111 是服務帳戶名稱
  • YOUR_PROJECT_ID 請換成自己的 project id

向服務帳戶授予權限

用您的專案 ID 取代 [PROJECT_ID]
#gcloud  projects  add-iam-policy-binding [PROJECT_ID] --member "serviceAccount:[NAME]@[PROJECT_ID].iam.gserviceaccount.com" --role "roles/monitoring.admin"

  • 所以這邊可以觀察到 監控管理員的權限是綁定在 project
  • roles/monitoring.admin 是觀察來的, 可以透過 #gcloud  projects  get-iam-policy [PROJECT_ID] 來看相關的權限

另外網路上也有看到找出服務帳戶 Role 的過濾方式

# gcloud projects get-iam-policy [PROJECT_ID] --flatten="bindings[].members" --filter="bindings.members:[NAME]@[PROJECT_ID].iam.gserviceaccount.com"

---
bindings:
  members: serviceAccount:sakanatest-20200111-monitor@xxxxxxx.iam.gserviceaccount.com
  role: roles/monitoring.admin
etag: BwWb1FtLJ4s=
version: 1

產生金鑰檔案

用金鑰檔案的名稱取代 [FILE_NAME]
#gcloud  iam  service-accounts  keys  create  [FILE_NAME].json --iam-account [NAME]@[PROJECT_ID].iam.gserviceaccount.com

created key [5abac9d47cd2g96386a05bad735d241d59a00897] of type [json] as [/root/test20200111.json] for [test20200111@xxxxxxxxx.iam.gserviceaccount.com]

  • 用指令的好處是可以直接指定憑證的位置, 我在下指令的時候是用 /root/test20200111.json

=================================

服務帳戶與金鑰準備好了之後, 接下來就是取得範例程式


更動的部分如下 ( 使用 diff 指令, 左邊是改寫, 右邊是 google 原來的範例 )

> diff snippets.py snippets-orig.py 

14,18d13
< # 
< # Edit by Max 2020/1/11
< # 因應工作需求, 改寫 snippets.py
< # File from https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/monitoring/api/v3/cloud-client
119,130d113
< # 改寫 list_time_series_aggregate
< # 
< # 這邊定義要查詢的區間
< query_time = input("Please input your query time in seconds, for example, 7 Days is 604800:  ") or 604800
< query_time_int=int(query_time) # 這邊將 query_time type 從 str 轉型為 int
< print("")
< cpu_threshold = input("Please input cpu usage under threshold, like 0.2 for 20%:  ") or 0.2
< cpu_threshold_float = float(cpu_threshold)
< print("")
140c123
<     interval.start_time.seconds = int(now - query_time_int) # 這邊用 query_time 來彈性調整
---
>     interval.start_time.seconds = int(now - 3600)
143c126
<     aggregation.alignment_period.seconds = query_time_int  # 這邊用 query_time 來彈性調整
---
>     aggregation.alignment_period.seconds = 1200  # 20 minutes
154,160c137
<       cpuUtil = result.points[0].value.double_value
<       if cpuUtil < cpu_threshold_float: #需要判斷的 CPU threshold, 用 cpu_threshold 來彈性調整
<           print("instance name:", result.metric.labels) # 列出 instance 名稱
<           # instance_id 是放在 resource.labels 下, 以字典的方式儲存, 所以透過 ['KEY_NAME'] 取出
<           print("instance id:", result.resource.labels['instance_id']) # 列出 instance id 來區別同樣名稱的 VM
<           print("CPU utilization:", cpuUtil *100, "% \n") # 列出 cpu 使用量
<     # print(result) 註解原來的方式
---
>         print(result)

接下來設定應用程式驗證作業需要的環境變數

定義 project , 請帶入自己 project ID
# export  GOOGLE_CLOUD_PROJECT=[PROJECT_ID]

定義剛剛的 json 檔案的路徑, 例如 /root/test20200111.json
# export GOOGLE_APPLICATION_CREDENTIALS="[path/key-name.json]"


確認有定義完成

# echo  $GOOGLE_CLOUD_PROJECT
# echo  $GOOGLE_APPLICATION_CREDENTIALS

使用 pip 安裝 python 相依性的套件
# pip  install  -r  requirements.txt

執行剛剛下載修改的 snippet.py

# python3  snippets.py  list-time-series-aggregate

Please input your query time in seconds, for example, 7 Days is 604800:  604800

Please input cpu usage under threshold, like 0.2 for 20%:  0.3

instance name: {'instance_name': 'test'}
instance id: 3255911329394624968
CPU utilization: 17.11500122 % 

instance name: {'instance_name': 'test2'}
instance id: 3713200083697575388
CPU utilization: 0.6797669215641027 % 

instance name: {'instance_name': 'test'}
instance id: 8590409858061083796
CPU utilization: 0.6412688036029409 % 

  • 這邊我改成互動的方式, 輸入要查詢的區間, 使用秒數爲單位
  • 輸入CPU 使用量的門檻值, 如果要列出 20% 以下就輸入 0.2

這樣就可以列出過去一週 CPU 小於 20 % 的 VM :)

另外補充, 當服務帳戶刪除的時候, 剛 members 與 Roles 還是在 project 上面, 所以要記得移除權限

例如
# gcloud projects remove-iam-policy-binding [PROJECT_ID] --member=serviceAccount:[NAME]@[PROJECT_ID].iam.gserviceaccount.com --role=roles/monitoring.admin

這樣又朝向 GCP 邁進一步

~ enjoy  it

Reference

三大雲平台工具容器升級小記 - 使用 python 3 with openSUSE Leap 15.1 Container

三大雲平台工具容器升級小記 - 使用 python 3  with openSUSE Leap 15.1 Container

OS: container with openSUSE Leap 15.1

上次升級是 2019/11/16 , 這次會來升級的原因是 
  • Google SDK 已經GA 支援 python 3,  274.0.0 以後的版本就支援 Python 3
  • awscli 使用 python 3 來安裝
  • Ansible with azure 使用 pip3 安裝

先整理結果

升級前
OS: openSUSE Leap 15.1
awscli:  aws-cli/1.16.282 Python/2.7.14
gcloud: Google Cloud SDK 271.0.0
azure-cli: 2.0.76

升級後
OS: openSUSE Leap 15.1
awscli:  aws-cli/1.16.310 Python/3.6.9
gcloud: Google Cloud SDK 274.0.1
azure-cli: 2.0.78

這次的做法還是會透過 docker build 指令來進行
  • 我有比較過 docker build 以及使用現有的 docker image 修改後再使用 docker commit 建立的 image 大小還是很有差異的

Dockerfile 的部分我是拿之前 openSUSE Leap 15.1 來修改

實際上只有修改
  • Update time
  • 使用 pip3 安裝 ansible[azure]
  • 使用 pip3 安裝 awscli
  • Google SDK 版本還有下載的檔案路徑以及檔案名稱


列出 diff 的結果給大家參考

> diff opensuseLeap151_ansible_Dockerfile opensuseLeap151_ansible_20200105_Dockerfile 

6c6
< # update: 20191122
---
> # update: 20200105
10,12c10,12
< RUN zypper install -y python2-pip && \
<   pip2 install --upgrade pip && \
<   pip2 install ansible[azure]
---
> RUN zypper install -y python3-pip && \
>   pip3 install --upgrade pip && \
>   pip3 install ansible[azure]
45c45
< RUN pip install awscli
---
> RUN pip3 install awscli
49c49
< # Install google cloud SDK 271
---
> # Install google cloud SDK 274.0.1
51,52c51,52
< RUN wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-271.0.0-linux-x86_64.tar.gz && \
<   tar zxvf google-cloud-sdk-271.0.0-linux-x86_64.tar.gz && \
---
> RUN wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-274.0.1-linux-x86_64.tar.gz && \
>   tar zxvf google-cloud-sdk-274.0.1-linux-x86_64.tar.gz && \




Dockerfile 內容如下

# openSUSE Leap 15.1 with ansible, azure-cli
FROM opensuse/leap:15.1

# Author
# MAINTAINER 已經棄用, 之後要使用 LABEL 方式
# update: 20200105
LABEL maintainer="sakana@cycu.org.tw"

# Install python2-pip, upgrade pip, ansible[azure]
RUN zypper install -y python3-pip && \
  pip3 install --upgrade pip && \
  pip3 install ansible[azure]

# Install openssh, set ls alias
RUN zypper install -y openssh
RUN echo "alias ls='ls --color=tty'" >> /root/.bashrc

# Install wget, download azure_rm.py, set permission
RUN zypper install -y wget && \
  wget  https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/azure_rm.py && \
  chmod a+x azure_rm.py && \
  mv azure_rm.py /root

# Create working directory in /root
RUN mkdir /root/.azure && \
  mkdir /root/.aws && \
  mkdir /root/playbook && \
  mkdir -p /root/.config/gcloud && \
  wget https://raw.githubusercontent.com/sakanamax/LearnAnsible/master/template/ansible.cfg && \
  mv /ansible.cfg /root && \
  wget https://raw.githubusercontent.com/sakanamax/LearnAnsible/master/template/hosts && \
  mv /hosts /root

# Install azure-cli
RUN zypper install -y curl && \
  rpm --import https://packages.microsoft.com/keys/microsoft.asc && \
  zypper addrepo --name 'Azure CLI' --check https://packages.microsoft.com/yumrepos/azure-cli azure-cli && \
  zypper install --from azure-cli -y azure-cli

#install vim tar gzip jq
RUN zypper install -y vim tar gzip jq
RUN echo "set encoding=utf8" > /root/.vimrc

# Install awscli
RUN pip3 install awscli
RUN echo "source /usr/bin/aws_bash_completer" >> /root/.bashrc


# Install google cloud SDK 274.0.1
ENV CLOUDSDK_CORE_DISABLE_PROMPTS 1
RUN wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-274.0.1-linux-x86_64.tar.gz && \
  tar zxvf google-cloud-sdk-274.0.1-linux-x86_64.tar.gz && \
  /google-cloud-sdk/install.sh && \
  echo "if [ -f '/google-cloud-sdk/path.bash.inc' ]; then . '/google-cloud-sdk/path.bash.inc'; fi" >> /root/.bashrc && \
  echo "if [ -f '/google-cloud-sdk/completion.bash.inc' ]; then . '/google-cloud-sdk/completion.bash.inc'; fi" >> /root/.bashrc



使用 docker build 指令建立 image

> docker build  -t  sakana/ansible_opensuse151:20200105  -f  ./opensuseLeap151_20200105_ansible_Dockerfile   .

  • 使用 -f 指定 Dockerfile 名稱
  • 最後是 ” . “ 目前的目錄


測試 container image

> docker  run  -v  ~/.aws:/root/.aws  -v  ~/.azure:/root/.azure  -v ~/.config/gcloud:/root/.config/gcloud  -it  sakana/ansible_opensuse151:20200105  /bin/bash

測試結果 OK, 建立  tag

觀察資訊
> docker  images

REPOSITORY                   TAG IMAGE ID           CREATED SIZE
sakana/ansible_opensuse151   20200105 06e961a97803        About a minute ago   1.32GB
sakana/ansible_opensuse151   latest 3d76040b20fb        6 weeks ago 1.19GB
opensuse/leap                15.1 fef5ad254f63        2 months ago 103MB

建立 tag 
> docker  tag  06e961a97803  sakana/ansible_opensuse151:latest

登入 docker
> docker  login

上傳 image
> docker  push  sakana/ansible_opensuse151:20200105

> docker  push  sakana/ansible_opensuse151:latest

完工, 以後使用就用

> docker  run  -v  ~/.aws:/root/.aws  -v  ~/.azure:/root/.azure  -v ~/.config/gcloud:/root/.config/gcloud  -it  sakana/ansible_opensuse151  /bin/bash


~ enjoy it

Reference:

MySQL Workbench 安裝與連接 Azure DB with openSUSE Leap 15.1 小記

MySQL Workbench 安裝與連接 Azure DB with openSUSE Leap 15.1 小記

OS: openSUSE Leap 15.1
MySQL Workbench: 8.0.15


只能再次說, Python 讀書會惠我良多 :p
之前有實驗 DB Browser for SQLite (sqlitebrowser)[1] 以及使用 mariadb-client 連線 Azure DB[2]

今天要來實作 MySQL Workbench 連接 Azure DB 部分

先來安裝 MySQL Workbench with openSUSE Leap 15.1
在 MySQL Workench 下載頁面上 https://dev.mysql.com/downloads/workbench/  沒有列出 openSUSE, 

到 MySQL 官網上觀察 6.3.10 是 2017-11-15 GA / 8.0.15 是 2019-02-01 GA, ( 最新是 8.0.18 )

如果要安裝 mysql-workbench, 要先裝 libantlr4-runtime4_7_2

  • 安裝 java:package 提供的 4.7.2 套件, 使用單鍵安裝方式
  • 沒有裝 libantlr4-runtime4_7_2 等等就會被告知相依性問題


接下來安裝 mysql-workbench
在 software.opensuse.org 搜尋 mysql-workbench  https://software.opensuse.org/package/mysql-workbench 看到有 6.3.10 以及 8.0.15



使用單鍵安裝的方式安裝 mysql-workbench 8.0.15 ( 由 server:database 提供 )
  • 點擊單鍵安裝, 他就是一個 .ymp 檔案, 下載之後打開就可以進行套件與套件庫安裝

開啟之後會出現 YaST2 視窗, 沒有意外就是下一步按到底就裝完了 :)


接下來在概覽內就會看到 MySQL Workbench 的圖示


雖然啟動的時候會很傷心的跟你說你的 OS 不支援( 雖然你可能用的好好的 )
點選 OK 進入程式



建立新的連線, 選取 [MySQL Connections] 標題旁邊的加號 (+) 圖示

輸入 連線名稱 / Hostname / Username


點選 Test Connection

接下來會被要求輸入密碼


如果輸入的資訊還有密碼都正確, 會告知有成功連線
點選 OK 回來視窗

再次點選 OK 結束新增連線設定



接下來就會看到主畫面就有剛剛設定的連線
點選剛剛設定的連線就會開啟 SQL Editor

會被詢問密碼, 然後開啟 SQL Editor



接下來進行簡單的 SQL 語法測試
輸入 show databases;
點選執行的閃電按鈕


結果會輸出到畫面下方

這樣又多了一個工具可以連接與管理 Azure DB 和練習 Python

Enjoy it ~


Reference:

Saturday

23 November, 2019

將GCP Stackdriver Alert 傳送到 telegram 小記

將GCP Stackdriver Alert 傳送到 telegram 小記

OS: container with openSUSE Leap 15.1

上次寫的是 “使用 Stackdriver 監控 GCE CPU 使用率, 超出監控值主動發出通知”, 通知的方式是 E-mail

那如果要更即時的方式呢?
所以接下來就來實驗透過 Telegram 來接受訊息 :)

首先要來建立 telegram bot

可以點選 以下網址 開啟 telegram 

或是在 telegram 程式中 

搜尋 @botfather


點選 START


接下來就會進入對話
也可以看到剛剛點選的 /start


輸入 /newbot 建立 bot

接下來會被要求輸入 bot 名稱, 這邊我以 sakana-gcp 為例子
輸入 sakana-gcp


然後是建立 bot 的使用者, 必須以 bot 結尾

我這邊以 sakana_gcp_bot 為例
輸入 sakana_gcp_bot
  • 這邊的命名規則不給輸入 - , 所以我用底線



建立完成會給 bot 的 HTTP API TOKEN


整理一下
  • Bot 名稱( 顯示名稱 ): sakana-gcp
  • Bot 使用者名稱(帳號): sakana_gcp_bot


接下來觀察 bot 是否可以加入群組

輸入 /setjoingroups
  • 預設是 Enable, 就是 bot 可以被加入群組
  • 如果被要求輸入 bot , 要輸入的是 bot 使用者名稱, @sakana_gcp_bot 


建立 Group



搜尋剛剛建立的 bot
點選 sakana-gcp , 點選其他要加入的人, 例如自己
點選 NEXT


輸入群組名稱
點選 CREATE GROUP 建立群組


接下來檢查是否可以查到已經加入群組的資訊, 以及 Group ID

使用 curl 指令 針對 bot 查詢資訊
> curl  https://api.telegram.org/botYOUR_TOKEN/getUpdates

{"ok":true,"result":[]}

  • 這邊的 YOUR_TOKEN 就是剛剛 @botfather 給的 TOKEN

  • 如果result 是空的, 就把 bot 從群組踢出去再加入一次, 再試試看

從資料中取得 Group Chat ID


使用 curl 確認是否可以用這個 Group Chat ID 發送訊息

>curl  -X  POST  "https://api.telegram.org/botYOUR_TOKEN/sendMessage"   -d "chat_id=YOUR_CHAT_ID&text=my sample text"

  • -X 是 request , -d 是 data
    • 注意雙引號各把 host 以及 data 內容標示住

成功的話應該會看到訊息



Cloudfunction 部分

使用 container 方式來建立相關程式
  • 要有 npm 套件, 等等在 container 內建立, 不影響自己環境

> docker  run  -v  ~/.aws:/root/.aws  -v  ~/.azure:/root/.azure  -v ~/.config/gcloud:/root/.config/gcloud  -it  sakana/ansible_opensuse151  /bin/bash



==== 在 contaienr 內 ( openSUSE Leap 15.1 with ansible and cloud tools ) ====

安裝 npm
# zypper  install  npm

Loading repository data...
Reading installed packages...
'npm' not found in package names. Trying capabilities.
Resolving package dependencies...

The following 8 NEW packages are going to be installed:
  libicu60_2 libicu60_2-ledata nodejs-common nodejs10 nodejs10-devel npm10 system-user-nobody timezone

8 new packages to install.
Overall download size: 17.8 MiB. Already cached: 0 B. After the operation, additional 71.0 MiB will be used.
Continue? [y/n/v/...? shows all options] (y): y


建立 telegram 目錄
# mkdir  telegram

進入 telegram 目錄
# cd  telegram

建立 index.js

# vi   index.js

const axios = require('axios');
// replace the value below with the Telegram token you receive from @BotFather
const token = '[YOUR_TOKEN]';
const chatId ='[YOUR_CHAT_ID]';
const url = `https://api.telegram.org/bot${token}/sendMessage`;
function sendMessage(msg) {
  return axios.post(url, {
   chat_id: chatId,
   text: msg,
});
}
exports.trigger = (req, res) => {
 const incident = req.body.incident;
 const policy = incident.policy_name;
 const cond = incident.condition_name;
 const state = incident.state;
 const url = incident.url;
 const msg = `${policy} ${cond} is ${state}, please check ${url}`
 console.log(msg);
 sendMessage(msg)
 .then(function (response) {
   console.error('invoke telegram');
   res.send({ status: 'OK'});
 })
.catch(function (error) {
  console.error(error);
  res.sendStatus(500);
 });
};

執行 npm init , 全都按照預設值

# npm  init

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (telegram) 
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /telegram/package.json:

{
  "name": "telegram",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes)  Y


安裝 axios 

# npm install axios

npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN telegram@1.0.0 No description
npm WARN telegram@1.0.0 No repository field.

+ axios@0.19.0
added 5 packages from 8 contributors and audited 5 packages in 2.123s
found 0 vulnerabilities

觀察相關資訊

# ls
index.js  node_modules  package-lock.json  package.json

# cat  package.json 

{
  "name": "telegram",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.19.0"
  }
}

佈署 cloud function ( 因為是用 container with cloud tools 環境, 所以有 gcloud 指令可以用 )

# gcloud  functions  deploy  trigger  --runtime  nodejs8  --trigger-http  --region  asia-east2 --project  YOUR_PROJECT_ID

  • trigger 是名稱
  • region 的部分, asia-east 只有 asia-east2
  • Project 後面請用自己的 project ID

輸出的訊息中會有 httpsTrigger URL , 等等會拿來使用

url: https://asia-east2-YOUR_PROJECT.cloudfunctions.net/trigger

另外還有一段警告訊息 
WARNING: Function created with limited-access IAM policy. To enable unauthorized access consider "gcloud alpha functions add-iam-policy-binding trigger --region=asia-east2 --member=allUsers --role=roles/cloudfunctions.invoker"



接下來建立 Stackdriver Webhook
點選專案內的選單 STACKDRIVER -- > Monitoring



在 Stackdriver 頁面
點選專案的下拉式選單 -- > 點選 Workspace Settings

點選 Notifications -- > 點選 WEBHOOKS -- > 點選 Add Webhook


填入  httpsTrigger URL 
填入 Webhook name



這個時候如果點選 Test Connection , 但是 Telegram bot 沒有傳送訊息
那就要回到 Container 內下剛剛被提示的指令

# gcloud  alpha  functions  add-iam-policy-binding  trigger  --region=asia-east2 --member=allUsers --role=roles/cloudfunctions.invoker


再次在 Webhook 頁面點選 Test Connection
會看到 undefind 訊息這樣就算是成功了


接下來就是可以針對 Stackdriver 的 alert 增加 telegram ( 使用 web hook 方式 )通知

選一個要加入的 Alert policy , 點選選單內的 Edit


在 Notification 的地方
請將下拉式選單拉到底 ~~ 才會看到 Webhook with Token Authentication


選取 剛剛建立的 Webhook 點選 Add Notification Channel


記得點選 Save 存檔


測試方式, 我的警示條件是 CPU 大於一定百分比就發出警告
  • 登入該台 VM, 使用 # stress-ng -c 4 --cpu-method all 進行壓測


接下來就會觀察到 telegram bot 送來相關訊息


Future work
  • Bot 的管控
  • Cloud function with iam policy binding 




這樣也算是向 Cloud function 前進一步了 :)

~ enjoy it


Notes: 刪除 telegram bot 方式



Reference



三大雲平台工具容器升級小記 with openSUSE Leap 15.1 container

三大雲平台工具容器升級小記 with openSUSE Leap 15.1 container

OS: container with openSUSE Leap 15.1

上次升級是 2019/8/3 , 這次會來升級的原因是 Google SDK 已經到了 271.0.0, 然後最近要作一個 Lab 需要 gcloud compute resource-policies 相關指令,  但是 Google SDK 245.0.0 沒有....
[ 謎之音: 需求是前進的鞭子 ~  ]

先整理結果

升級前
OS: openSUSE Leap 15
awscli:  aws-cli/1.16.210 Python/2.7.14
gcloud: Google Cloud SDK 245.0.0
azure-cli: 2.0.70

升級後
OS: openSUSE Leap 15.1
awscli:  aws-cli/1.16.282 Python/2.7.14
gcloud: Google Cloud SDK 271.0.0
azure-cli: 2.0.76

Todo
  • 12 月的時候將 awscli 用 python3 安裝
    • 原因是 Google SDK 目前還是 Python2, 所以想要一起升級 :p

這次的做法會透過 docker build 指令來進行
  • 我有比較過 docker build 以及使用現有的 docker image 修改後再使用 docker commit 建立的 image 大小還是很有差異的

Dockerfile 的部分我是拿之前 openSUSE Leap 15 來修改

實際上只有修改
  • openSUSE Leap 版本
  • Update time
  • Google SDK 版本還有下載的檔案路徑以及檔案名稱


列出 diff 的結果給大家參考

> diff  opensuseLeap151_ansible_Dockerfile  opensuseLeap15_ansible_Dockerfile 

1,2c1,2
< # openSUSE Leap 15.1 with ansible, azure-cli
< FROM opensuse/leap:15.1
---
> # openSUSE Leap 15 with ansible, azure-cli
> FROM opensuse/leap:15
6c6
< # update: 20191116
---
> # update: 20190727
49c49
< # Install google cloud SDK 271
---
> # Install google cloud SDK 240
51,52c51,52
< RUN wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-271.0.0-linux-x86_64.tar.gz && \
<   tar zxvf google-cloud-sdk-271.0.0-linux-x86_64.tar.gz && \
---
> RUN wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-245.0.0-linux-x86_64.tar.gz && \
>   tar zxvf google-cloud-sdk-245.0.0-linux-x86_64.tar.gz && \


Dockerfile 內容如下

# openSUSE Leap 15.1 with ansible, azure-cli
FROM opensuse/leap:15.1

# Author
# MAINTAINER 已經棄用, 之後要使用 LABEL 方式
# update: 20191116
LABEL maintainer="sakana@cycu.org.tw"

# Install python2-pip, upgrade pip, ansible[azure]
RUN zypper install -y python2-pip && \
  pip2 install --upgrade pip && \
  pip2 install ansible[azure]

# Install openssh, set ls alias
RUN zypper install -y openssh
RUN echo "alias ls='ls --color=tty'" >> /root/.bashrc

# Install wget, download azure_rm.py, set permission
RUN zypper install -y wget && \
  wget  https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/azure_rm.py && \
  chmod a+x azure_rm.py && \
  mv azure_rm.py /root

# Create working directory in /root
RUN mkdir /root/.azure && \
  mkdir /root/.aws && \
  mkdir /root/playbook && \
  mkdir -p /root/.config/gcloud && \
  wget https://raw.githubusercontent.com/sakanamax/LearnAnsible/master/template/ansible.cfg && \
  mv /ansible.cfg /root && \
  wget https://raw.githubusercontent.com/sakanamax/LearnAnsible/master/template/hosts && \
  mv /hosts /root

# Install azure-cli
RUN zypper install -y curl && \
  rpm --import https://packages.microsoft.com/keys/microsoft.asc && \
  zypper addrepo --name 'Azure CLI' --check https://packages.microsoft.com/yumrepos/azure-cli azure-cli && \
  zypper install --from azure-cli -y azure-cli

#install vim tar gzip
RUN zypper install -y vim tar gzip
RUN echo "set encoding=utf8" > /root/.vimrc

# Install awscli
RUN pip install awscli
RUN echo "source /usr/bin/aws_bash_completer" >> /root/.bashrc


# Install google cloud SDK 271
ENV CLOUDSDK_CORE_DISABLE_PROMPTS 1
RUN wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-271.0.0-linux-x86_64.tar.gz && \
  tar zxvf google-cloud-sdk-271.0.0-linux-x86_64.tar.gz && \
  /google-cloud-sdk/install.sh && \
  echo "if [ -f '/google-cloud-sdk/path.bash.inc' ]; then . '/google-cloud-sdk/path.bash.inc'; fi" >> /root/.bashrc && \
  echo "if [ -f '/google-cloud-sdk/completion.bash.inc' ]; then . '/google-cloud-sdk/completion.bash.inc'; fi" >> /root/.bashrc

使用 docker build 指令建立 image

> docker build  -t  sakana/ansible_opensuse151:20191116  -f  ./opensuseLeap151_ansible_Dockerfile   .

  • 使用 -f 指定 Dockerfile 名稱
  • 最後是 ” . “ 目前的目錄


測試 container image

> docker  run  -v  ~/.aws:/root/.aws  -v  ~/.azure:/root/.azure  -v ~/.config/gcloud:/root/.config/gcloud  -it  sakana/ansible_opensuse151:20191116  /bin/bash

測試結果 OK, 建立  tag

觀察資訊
> docker  images

REPOSITORY                   TAG IMAGE ID           CREATED SIZE
sakana/ansible_opensuse151   20191116 dcd69d00b4aa        34 minutes ago      1.19GB
opensuse/leap                15.1 fef5ad254f63        10 days ago 103MB
sakana/ansible_opensuse15    latest 4fe595fb61e4        3 months ago 1.1GB

建立 tag 
> docker  tag  dcd69d00b4aa  sakana/ansible_opensuse151:latest

登入 docker
> docker  login

上傳 image
> docker  push  sakana/ansible_opensuse151:20191116

> docker  push  sakana/ansible_opensuse151:latest

完工, 以後使用就用

> docker  run  -v  ~/.aws:/root/.aws  -v  ~/.azure:/root/.azure  -v ~/.config/gcloud:/root/.config/gcloud  -it  sakana/ansible_opensuse151  /bin/bash


~ enjoy it

Reference: