顯示文章

這裡允許您檢視這個會員的所有文章。請注意, 您只能看見您有權限閱讀的文章。


文章 - netman

頁: [1] 2 3 ... 500
1
Linux 討論版 / Re: linux的shell脚本
« 於: 2020-04-05 15:16 »
你怎運行的? 結果是怎樣?

2
DevOps 討論版 / K8S 之 Cert-Manager 建置
« 於: 2020-03-16 22:05 »
K8S 之 Cert-Manager 建置
netman <netman@study-area.org>
2020.03

一,前言
當 K8S 玩到一個階段的時候,自然會遇到 cert-manager 的需求。別問我爲什麼,反正有很多機會遇到就是了。然而,很多朋友都跟我一樣發現 cert-manager 似乎沒那麼好上手。因爲還需要扯上一些基本的 PKI 概念,但這裏先不展開 certificate 相關的基礎了,有興趣的朋友可以另外學習。

此外,這裏也不對 cert-manager 的基本概念多做闡述,請大家到官網瞭解吧:
   https://cert-manager.io/docs/

本篇的要旨主要是以實作的方式來示範 k8s 上的 cert-manager 建置過程。因爲 cert-manager 也有不同的方式搭建,這裏也只就本人偏好的其中一種來示範而已。

二,先讓我們 Let's Encrypt 吧!
基本上,k8s 的 cert-manager 可以使用不同的憑證來源發佈憑證,例如 Let’s Encrypt、HashiCorp Vault、Venafi,甚至是簡單的金鑰組或自簽憑證。爲求實用性,這裏就以當今最熱門且又是免費的 Let's Encrypt 來做示範。

Let's Encrypt 本身就是一個憑證發行機構(CA),主要透過 ACME 協定來確認 domain 擁有者身份並進行憑證的後續處理任務。其配置方式也有很多種,例如使用 Certbot 或是透過網站空間服務商內建支援等等。不過,這篇的目的是用 k8s 的 cert-manager 來處理憑證問題,所以一開始我們只需要一種簡單的方式來驗證 Let's Encrypt 是否成功即可。這裏,我選擇了acme.sh 這隻純 shell 的腳本來幫忙驗證。

Let's Encrypt 一般是透過連線您的 web server 來驗證身份,但這方式必須要提供一個可供外部連線的網站服務。有時對於純內部的使用環境來說卻是一件麻煩的事情。但 Let's Encrypt 也同時提供另外一種驗證方式,就是透過 DNS 查詢來確定您的合法性。

目前有不少主流 DNS 服務商都有提供 Let's Encrypt 的支援,例如 CloudFlare,允許我們透過 API 的方式修改 DNS Record 從而通過 Let's Encrypt 的驗證。這裏,我將使用 CloudFlare 作爲 Let's Encrypt 的 DNS 驗證。

2.1 取得 CloudFlare API Token
首先,請登入 ClouldFlare 的 dashbord,然後從右上角的 My Profile 那邊選擇 API Tokens:


然後按下 Create Token 按鈕,根據自己喜好輸入 Token Name,將 Permissions 設定如下:
  • Zone, Zone, Read
  • Zone, DNS, Edit


然後按 Continue to summary,確認權限後再按 Create Token ,最後跳出的視窗會列出 Token 的內容,請 Copy 下來保存。(網頁也有顯示測試 token 的方法,不妨也複製下來測試驗證。)

此外還有一件事情:您必須確定 CloudFlare 帳號中所留的 Email 已經完成驗證。

2.2 使用 acme.sh
操作者不一定需要 root 的權限(有則更好),直接線上安裝就行:
curl https://get.acme.sh | sh

然後登出再重新登入即可操作 acme.sh 。

首先,將 CloudFlare 那邊的 API Token 與 Email 設定爲環境變數:
export CF_Token="1txxxxqP-xxxxxxxxxxxxxxTp5JIxxxxxnf"
export CF_Email="xxx@xxxx.xxxx.com"

我這裏打算建立 wildcard 憑證,所以直接輸入如下命令:
acme.sh --issue -d k8slab.exmaple.com  -d '*.k8slab.example.com'  --dns dns_cf
(注意:example.com 只是個舉例,請修改爲真正的 domain 名稱。)

如果沒有 error,最終會生出如下內容:
Your cert
Your cert key
The intermediate CA cert
The full chain certs

日後要 renew 憑證的話,只需執行如下命令即可:
acme.sh --renew --force -d k8slab.exmaple.com  -d '*.k8slab.example.com'  --dns dns_cf

當 acme.sh 測試成功之後,然後我們再轉移到 k8s 中設定 cert-manager 。

三,在 K8S 配置 cert-manager
在 cert-manager 的官網文件(https://cert-manager.io/docs/)中我們可以獲得很多配置資訊。然而,關於 ACME 底下的 CloudFlare 部份卻沒有很完整的範例。建議交叉參考網路上其他文章來獲得適當的設定。下面的過程我會將建置流程中特別需要注意的地方強調出來,減少大家的試誤時間。

3.1 安裝 cert-manager
基本上按照官網的 Installation 就可以了,以下是我整理的步驟:
mkdir cert-manager
cd cert-manager
kubectl create namespace cert-manager
wget https://github.com/jetstack/cert-manager/releases/download/v0.13.1/cert-manager.yaml
kubectl apply -f cert-manager.yaml
kubectl get pods --namespace cert-manager

最後的驗證結果請確定所有的 pod 都處於 Running 狀態:


其中要留意的地方是 cert-manager-webhook 需要比較久一些時間才能從 ContainerCreating 變成 Running 狀態,請耐心等候就是了。

3.2 配置 secret
接下來,我們要將 CloudFlare 的 API Token 以 secret 的方式進行配置。請建立一份 secret.yaml:
代碼: [選擇]
apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token-secret
  namespace: cert-manager
type: Opaque
stringData:
  api-token: 1txxxxqP-xxxxxxxxxxxxxxTp5JIxxxxxnf

這裏要特別留意的地方在於 namespace :如果採用 Issuer 而非 ClusterIssuer 的話,就不需要設定。但我這裏要示範的 issuer 是用 ClusterIssuer,因此必需要將 namespace 設定爲 cert-namager,也就與 cert-manager pod 相同的 namespace 就是了。如果這裏設定不對的話,在產生 Challenge 的時候,會遇到找不到 secret 的錯誤。這個細節花了我相當多的時間才搞懂,希望可以節省大家寶貴的時間!

3.3 配置 ClusterIssue
在 K8S 的 cert-manager 中,可以使用的 issuer 有兩種:
Issuer: 只能讓相同 namespace 裏面的憑證使用
ClusterIssuer: 不分 namespace,整個 cluster 內的憑證都可以使用

由於 ClusterIssuer 的通用性比較高,因此我採用這一方式來發行後續的憑證。這裏請建立一份 cluster-issuer.yaml:
代碼: [選擇]
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
  name: k8slab-issuer
  namespace: cert-manager
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: cert-k8slab
    solvers:
    - dns01:
        cloudflare:
          email: xxx@xxxx.xxxx.com
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token

與 secret 一樣,因爲 ClusterIssuer 的關係,這裏也是要設定 namespace。另外一個要注意的地方是 email 要與 CloudFlare 驗證的郵件信箱一致。而 apiTokenSecretRef 所用的 name 必須與  secret 的名字一致才行。

3.4 配置 Certificate
這裏是最後要設定的憑證了,請建立一份 cert.yaml :
代碼: [選擇]
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: k8slab-cert
  namespace: default
spec:
  secretName: k8slab-cert-tls
  issuerRef:
    name: k8slab-issuer
    kind: ClusterIssuer
  commonName: '*.k8slab.example.com'
  dnsNames:
  - k8slab.example.com
  - "*.k8slab.example.com"

請留意 spec 底下的 secretName 並不是指前面建立的 secret 名稱,而是給憑證暫用的參考名稱而已,因此兩個名字是不一樣的。這裏只需要確定 issuerRef 的正確性就好。因爲我要配置通配型(wildcard)憑證,因此我的 dnsName有兩個:一個帶星號(*)、另一個沒有。

3.5 套用配置
當上述三個 yaml 檔案配置完成後,接下來當熱就是套用並測試了:
kubectl apply -f secret.yaml
kubectl apply -f cluster-issuer.yaml
kubectl apply -f cert.yaml

如果 yaml 沒有打錯字的話,一般來說上面的資源都會順利 created 。稍等幾分鍾(我建議等個3分鐘左右),然後就可以驗證憑證是否有配置成功:
kubectl describe Certificate

如果最後看的 Status 顯示爲 Ready/True 的話:


恭喜您!您的 Cert-Manager 已經配置成功了!

3.6 除錯
有實務經營的朋友通常都會發現事情一般來說都不會那麼順利的!

那麼,當有問題時要如何除錯呢?這才是重點中的重點啊。假如我們套用 yaml 之後發現憑證狀態一直都卡在 InProgress 的狀態:


以根據上面的 Message 可得到 Waiting 的對象是 CertificateRequest,並且 Events 中也看到 CertificateRequest 被創建出來了,那麼接下來我們就可以查詢 CertificateRequest:
kubectl describe CertificateRequest

然後,我們或許會看到如下的訊息:


從上面的訊息中,我們又發現 Order 被創建出來並且在等待中,因此我們就接下來查詢 Order 就是了:
kubectl describe Order

從結果中我們可以看到:


其中有兩個 Challenge 被創建出來,於是我們就繼續查 Challenge:
kubectl describe Challenge

仔細檢查裏面的資訊,可能會發現類似這樣的內容:


這裏很明顯看到錯誤原因是 secret "cloudflare-api-token-secret" not found 嘛!我就是根據這個資訊去 google 才發現是 namespace 的問題!

如果 Challenge 沒問題的話,一般我們會看到這樣的資訊:


而另外一個 Challenge 則顯示爲 Waiting for dns-01 challenge propagation 的狀態... 這時候只需要耐心等候幾分鍾就好。最後會從 Order 中看到 successfully 的結果:


從 CertificateRequest 的查詢結果也會看到成功才對:


四,結語
希望以上的分享能夠幫助大家順利完成 K8S 的 cert-manager 建置。遇到問題時,請多看官方的文件,按部就班設定一般都能成功的。請記住 google 大神永遠都在,有拜有包庇哦!

--- END ---




3
這個真沒研究過呢...
我都是手機分享熱點,然後手機用 wifi 去連...

4
使用k8s externel-dns自動更新BIND DNS

2020.02

一,需求背景

在 Kubernetes 的管理中,服務名稱的解釋在 cluster 內幾乎不需要操心就能直接使用。然而,很多時候,我們建置好的服務是提供給 cluster 之外的用戶端作存取的,一般來說用戶端都以 DNS 名稱來存取服務。倘若每一筆服務都要人工方式更新 DNS 紀錄的話,這顯然不能滿足當今的營運需求。

為此,我們可以從 https://github.com/kubernetes-sigs/external-dns 取得 External DNS for Kubernetes 這一工具幫我自動完成 DNS 的更新。

二,External DSN 簡介

   External DNS 可以將 K8S 中的 Service 與 Ingress 這兩種資源的名稱解釋同步到外部的 DNS 伺服器。也就是說,當資源產生的時候自動新增 hostname 與 IP 的記錄,並在資源刪除的時候一併移除 DNS 記錄。

External DNS 支援的外部 DNS 非常多,幾乎網際網路上各家提供動態 DNS 更新服務的服務商都在其支援之列,例如:
  • AWS Route 53
  • Google Cloud DNS
  • AzureDNS
  • CloudFlare
  • Dyn
  • ….

早期的 external-dns 版本並不支援 BIND,好消息是最新的版本提供了一個 RFC2136 的 provider 讓我們用 dns-key 來更新 BIND DNS 伺服器了!(Microsoft DNS也是支援的,但目前沒有提供連線加密的方式)

三,實作環境

本文章將示範如何利用 External DNS 將 K8S 的服務資源名稱同步到不在 cluster 中的 Linux BIND 伺服器:
  • Linux: CentOS Linux release 7.6.1810 (Core)
  • BIND: bind-9.9.4-74.el7_6.1.x86_64
  • IP: 192.168.100.1

K8S Cluster則是使用 kubeadm建置完成:
  • Kubernetes: v1.16.2

四,設定 BIND 的 dns update 功能

4.1 產生 dns key:
代碼: [選擇]
cd /var/named/dynamic
dnssec-keygen -a hmac-sha256 -b 128 -n HOST externaldns-key
chown named.named Kexternaldns-key.*
cat Kexternaldns-key.*.key | awk '{print $NF}'
確定輸出類似 y+gUcHxLWqzg3JcBU2bbgw== 的結果,並複製結果。

4.2 修改 named.conf,末尾處增加如下內容:
代碼: [選擇]
key "externaldns-key" {
    algorithm hmac-sha256;
    secret "y+gUcHxLWqzg3JcBU2bbgw==";
};
zone "k8s.example.org" {
    type master;
    file "/var/named/dynamic/named.k8s.example.org";
    allow-transfer {
        key "externaldns-key";
    };
    update-policy {
        grant externaldns-key zonesub ANY;
    };
};
注意:secret 內容請用複製的key貼上。

4.3 建立 zone file (/var/named/dynamic/named.k8s.example.org)內容:
代碼: [選擇]
$TTL 60 ; 1 minute
@         IN SOA  k8s.example.org. root.k8s.example.org. (
                                16         ; serial
                                60         ; refresh (1 minute)
                                60         ; retry (1 minute)
                                60         ; expire (1 minute)
                                60         ; minimum (1 minute)
                                )
                        NS      ns.k8s.example.org.
ns                      A       192.168.100.1
注意:BIND server 的 IP 請修改實際 IP。

4.4 重新啟動 named 服務:
代碼: [選擇]
systemctl restart named
systemctl status -l named
確定沒有 error,並且 k8s.example.org 的 serial 是正確的。

五,建置 metallb Load Balancer (Optional)
# 如果 K8S Cluster 已經有可用的 Load Balancer 可略過此一步驟。

5.1 下載 metallb yaml 並套用:
代碼: [選擇]
wget https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml
sed -i '/^apiVersion: apps/s/beta2//' metallb.yaml
kubectl apply -f metallb.yaml
因為我們這裡的 k8s 版本已經升級到 v1.16, 因此需要調整 api 的版本。若您的環境是 v1.15 或之前的版本, 請略過 sed 那行指令不要執行。

5.2 建立 metallb configmap (metallb_configmap.yaml),其內容如下:
代碼: [選擇]
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: my-ip-space
      protocol: layer2
      addresses:
      - 192.168.100.240-192.168.100.249
請將 ip range 修改爲實際的網段,這是分配給 k8s service 資源用的 IP。完成後套用即可:
kubectl apply -f metallb_configmap.yaml
如果沒有 error 就表示就緒了。

六,佈署 external-dns

6.1 撰寫yaml (external-dns.yaml),其內容如下:
代碼: [選擇]
apiVersion: v1
kind: Namespace
metadata:
  name: external-dns
  labels:
    name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: external-dns
  namespace: external-dns
rules:
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - get
  - watch
  - list
- apiGroups:
  - extensions
  resources:
  - ingresses
  verbs:
  - get
  - list
  - watch
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
  namespace: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
  namespace: external-dns
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
- kind: ServiceAccount
  name: external-dns
  namespace: external-dns
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
  namespace: external-dns
spec:
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: registry.opensource.zalan.do/teapot/external-dns:v0.5.17
        args:
        - --provider=rfc2136
        - --registry=txt
        - --txt-owner-id=k8s
        - --source=service
        - --source=ingress
        - --domain-filter=k8s.example.org
        - --rfc2136-host=192.168.100.1
        - --rfc2136-port=53
        - --rfc2136-zone=k8s.example.org
        - --rfc2136-tsig-secret=y+gUcHxLWqzg3JcBU2bbgw==
        - --rfc2136-tsig-secret-alg=hmac-sha256
        - --rfc2136-tsig-keyname=externaldns-key
        - --rfc2136-tsig-axfr
        #- --interval=10s
        #- --log-level=debug
最後兩行是方便 debug 時用的,需要的時候才移除掉 # 註解符號。設定中比較關鍵的是 dns server 與 key 的正確性,請特別留意。

6.2 佈署服務:
代碼: [選擇]
kubectl apply -f external-dns.yaml如果沒有 error 就表示就緒了。

七,建置測試服務 (nginx)

7.1 撰寫服務 yaml (nginx.yaml),其內容如下:
代碼: [選擇]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  annotations:
    external-dns.alpha.kubernetes.io/hostname: nginx.k8s.example.org
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  sessionAffinity: None
  type: LoadBalancer
External-dns 最關鍵的部分就是要從 service 的 annotations 取得 hostname,然後再抓取 Load Balancer 分配的 IP 進行 dns update。

7.2 佈署服務:
代碼: [選擇]
kubectl apply -f nginx.yaml如果沒有 error 就表示就緒了。

7.3 觀察結果:
代碼: [選擇]
kubectl -n external-dns logs external-dns-5d986694c9-5n9wm請注意實際運行的 pod 名稱或許不太一樣,請調整。如果一切順利,從輸出結果中可以看到類似如下的內容:
代碼: [選擇]
time="2019-12-04T16:26:44Z" level=info msg="Created Kubernetes client https://10.96.0.1:443"
time="2019-12-04T16:26:49Z" level=info msg="Configured RFC2136 with zone 'k8s.example.org.' and nameserver '192.168.100.1:53'"
time="2019-12-04T16:26:49Z" level=info msg="Adding RR: nginx.k8s.example.org 0 A 192.168.100.245"
time="2019-12-04T16:26:49Z" level=info msg="Adding RR: nginx.k8s.example.org 0 TXT \"heritage=external-dns,external-dns/owner=k8s,external-dns/resource=service/default/nginx-svc\""

另外, 從 BIND 伺服器那邊, 也可以用 systemctl status -l named 觀察更新的動作,當然也可以用 dig 或 host 命令來實際檢查 dns 的查詢結果。假如名稱解釋一如預期,那就用瀏覽器連線服務的 hostname 來作最後的確認。

八,其他

前面我們是用 service 資源來作示範。假如 k8s 環境中已經建置好 ingress-controller 的話,那我們也可以透過建置 ingress 來同步 dns 的更新。我們只需要設定 ingress 資源並進行套用即可:
代碼: [選擇]
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
    name: nginx-ingress
spec:
    rules:
    - host: ingress.k8s.example.org
      http:
          paths:
          - path: /
            backend:
                serviceName: nginx-svc
                servicePort: 80
請留意使用 ingress 比 service 會稍有不同:
  • 不需要設定 annotations 來指定 hostname
  • IP 一律共用 ingress 服務的位址

假如我們要將服務資源停掉的話,也可以透過前述的檢查動作觀察到 dns 名稱也會自動地被刪除:
代碼: [選擇]
12月 05 00:43:49 srv1.localdomain named[6533]: client 192.168.100.56#58519/key externaldns-key: updating zone 'k8s.example.org/IN': deleting rrset at 'nginx.k8s.example.org' A
12月 05 00:43:49 srv1.localdomain named[6533]: zone k8s.example.org/IN: sending notifies (serial 21)
12月 05 00:43:49 srv1.localdomain named[6533]: client 192.168.100.56#45520/key externaldns-key: updating zone 'k8s.example.org/IN': deleting rrset at 'ingress.k8s.example.org' A
12月 05 00:43:49 srv1.localdomain named[6533]: client 192.168.100.56#49731/key externaldns-key: updating zone 'k8s.example.org/IN': deleting rrset at 'nginx.k8s.example.org' TXT
12月 05 00:43:49 srv1.localdomain named[6533]: client 192.168.100.56#56605/key externaldns-key: updating zone 'k8s.example.org/IN': deleting rrset at 'ingress.k8s.example.org' TXT

九,結語

好了,到這裡我們已經體驗到 external-dns 帶來的便利性。希望能夠對大家在 k8s 應用上有所幫助。

--- End ---

5
Linux 討論版 / Re: 关于模拟MBR损坏的修复
« 於: 2020-02-17 13:17 »
照理說 446 byte 只改掉 loader 而已,你描述的似乎連第一個 partition 也被蓋掉..
下次先將原來的 save 出來吧

6
Linux 討論版 / Re: 关于RHEL7系统启动错误
« 於: 2020-02-17 13:15 »
有跑過 grub2-mkconfig 嗎?

https://wiki.centos.org/zh-tw/HowTos/Grub2

7
用Pi做IoT,是在學Linux...+1

8
Linux 討論版 / Re: 架設DNS有問題
« 於: 2019-11-15 09:25 »
journalctl -el 先看看 named 的 log 有沒有載入這個 domain 且 serial 號碼是否一致?
再來確認  udp 53 port 是否有再所有界面上提供服務?
最後確認 client 的  resolv.conf 是否將 dns server 設定在第一順位。

9
雜七雜八 / Re: 歡迎一起來 MOPCON 2019
« 於: 2019-11-01 14:34 »
沒親身聽到 HOYO大師 演講真是可惜,光是看簡報內容就覺得十分精彩!!  ;D

有畫面...

10
disk space 超過 95% ?

11
linux 的 NAT 有分兩種:SNAT(masqurating) 與 DNAT(port mapping)
如果你要單純做 SNAT,那用外面來 ping 是徒勞的。
ping 是 ICMP 協定的 echo request ,你需要用 DNAT 將相應的 icmp type/code 給 forward 到特定得 destination。
這不一定需要兩片網路卡。

我在 n 年前寫過一篇介紹 linux firewall 的文章,不妨參考看看:
https://www.slideshare.net/kennychennetman/linux-firewall-32337622
如果對 Part-V 的問題都能理解,應該就可以解決大部分問題了。

12
那外面 ping 不到是正常的。NAT 之後,外面的 ping 不進來的。

13
等等,你這裡的host是實體主機?

14
老實說,有點看不太懂你畫的圖。

如果是 bridge mode,我會畫成這樣附件那樣。(紅色爲 vm)

15
基本上,經過 NAT 之後, 外面是無法 PING 進來的。
除非你用 routing mode(不同subnet) 或用 bridge(相同subnet)
用 routing 的話, 那需要雙方設定 gateway 互相指向。

16
你可以用附件功能將圖貼上來哦

17
工作機會 / Re: KKStream 獨家工作機會
« 於: 2019-08-22 10:40 »
好工作!不做嗎?

18
可以畫個網路架構圖來看看嗎?

19
Linux 討論版 / Re: Cent 6.10搭建FTP服务器问题
« 於: 2019-08-20 22:13 »
1. 如果 chmod 777 可以的話,那幾乎可以排除是 selinux 的影響。
chown_uploads=YES
chown_username=SAS
anon_umask=077
因爲你使用了 chown,上傳後身份就改變了,所以 guest 會無法 ls / dir 那是正常的。
這其實也是匿名上傳的建議做法,沒啥不好,並非遇到問題了。

2. 在匿名上傳的 ftp 管理中,需要本機的管理員檢核過上傳的文件,再決定是否開放匿名 ftp 下載,若覺得可以,執行 chown vsftpd 修改允許之文件即可。

20
那不要直接用 ntfs 格式呢?
也就是先用 xfs 或 ext4 掛載到 centos,然後再於裏面創建虛擬硬盤給 windows,然後再格式化爲 NTFS 。

21
Study-Area 公開討論版 / Re: 新人报道
« 於: 2019-08-14 21:42 »
歡迎啊~

非常感謝您的意見!因爲網站好久沒維護了,不足之處還請多多包涵~~

22
Linux 討論版 / Re: root帳號修改密碼被限制
« 於: 2019-08-08 20:27 »
具體的 error 是什麼呢?

23
Runing a descheduler on your own K8S cluster

v1.0
2019-08-01


一,前言

當我們建置完成一個多 worker nodes 的 K8S cluster 之後,本身就能提供相當的容錯能力。也就是當其中一臺 worker 節點故障或是用 drain 命令排除的時候,運行其上的 pods 會自動轉移至其他良好的 worker 節點上。然而,當故障節點修復上線或用 uncordon 命令加回 cluster 之後,已經處於運行狀態的 pods 並不會自動轉移回康復節點, 只有新產生的 pods 才會被安排在其上運行。

有時候,不同的 node 或因資源不同或因工作量不同,會導致各自有不同的負載:有些節點很忙、有些則很閒。

爲解決上述情況,除了管理員人爲調配之外,我們也可以藉助一個名爲 DeScheduler 的工具來實現服務的自動化平衡調度。


二,關於 DeScheduler

如下爲 DeScheduler 的 GitHub:
   https://github.com/kubernetes-incubator/descheduler

有興趣的朋友可以先去瞭解它的設檔細節,尤其是其中的 Policy and Strategies:
  • RemoveDuplicates
  • LowNodeUtilization
  • RemovePodsViolatingInterPodAntiAffinity
  • RemovePodsViolatingNodeAffinity

這裏暫時不討論這 4 種基本策略的內容了,我們只需要將所要的策略配置爲 ConfigMap 即可(一個單一的 ConfigMap 可以配置多個策略)。


三,部署 DeScheduler

3.1 建立一個空白目錄:
代碼: [選擇]
mkdir descheduler-yaml
cd descheduler-yaml

3.2 建置 ClusterRole & ServiceAccount:
代碼: [選擇]
cat > cluster_role.yaml << END
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: descheduler
  namespace: kube-system
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "watch", "list"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list", "delete"]
- apiGroups: [""]
  resources: ["pods/eviction"]
  verbs: ["create"]
END
kubectl apply -f cluster_role.yaml
kubectl create sa descheduler -n kube-system
kubectl create clusterrolebinding descheduler \
    -n kube-system \
    --clusterrole=descheduler \
    --serviceaccount=kube-system:descheduler

3.3 配置 ConfigMap:
代碼: [選擇]
cat > config_map.yaml << END
apiVersion: v1
kind: ConfigMap
metadata:
  name: descheduler
  namespace: kube-system
data:
  policy.yaml: |- 
    apiVersion: descheduler/v1alpha1
    kind: DeschedulerPolicy
    strategies:
      RemoveDuplicates:
         enabled: true
      LowNodeUtilization:
         enabled: true
         params:
           nodeResourceUtilizationThresholds:
             thresholds:
               cpu: 20
               memory: 20
               pods: 20
             targetThresholds:
               cpu: 50
               memory: 50
               pods: 50
      RemovePodsViolatingInterPodAntiAffinity:
        enabled: true
      RemovePodsViolatingNodeAffinity:
        enabled: true
        params:
          nodeAffinityType:
          - requiredDuringSchedulingIgnoredDuringExecution
END
kubectl apply -f config_map.yaml

#注意: 這裏我們將 RemoveDuplicates 策略設定爲啓用(enabled: true),如果不需要自動將 pods 分配到新成員節點的話,可以設定爲停用(enabled: false)。如果系統資源充足而達不到觸發條件,可以調低 LowNodeUtilization 策略的 thresholds 數值(cpu, momory, pod 數量,這三者要同時滿足才能觸發作動)。

3.4 配置 CronJob:
代碼: [選擇]
cat > cron_job.yaml << END
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: descheduler
  namespace: kube-system
spec:
  schedule: "*/30 * * * *"
  jobTemplate:
    metadata:
      name: descheduler
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: "true"
    spec:
      template:
        spec:
          serviceAccountName: descheduler
          containers:
          - name: descheduler
            image: komljen/descheduler:v0.6.0
            volumeMounts:
            - mountPath: /policy-dir
              name: policy-volume
            command:
            - /bin/descheduler
            - --v=4
            - --max-pods-to-evict-per-node=10
            - --policy-config-file=/policy-dir/policy.yaml
          restartPolicy: "OnFailure"
          volumes:
          - name: policy-volume
            configMap:
              name: descheduler
END
kubectl apply -f cron_job.yaml

# 注意:這裏設定的 CronJob 是每 30 分鐘執行一次,假如想在測試時更快驗證效果,可以調整爲更短的時間。


四,驗證

4.1 確認 CronJob:
代碼: [選擇]
kubectl get cronjobs -n kube-system確定可以看到類似如下的結果:
NAME          SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
descheduler   */30 * * * *   False     0         2m              32m


4.2 確認完成工作的 pods:
代碼: [選擇]
kubectl get pods -n kube-system | grep Completed會看到類似如下的結果:
descheduler-1564670400-67tqx                   0/1     Completed   0          1H
descheduler-1564670700-2vwhv                   0/1     Completed   0          32m
descheduler-1564671000-g69nc                   0/1     Completed   0          2m


4.3 檢查 logs:
代碼: [選擇]
kubectl -n kube-system logs descheduler-1564671000-g69nc如果沒觸發任何作動的話,最後一行會類似如下:
...
I0505 11:55:08.160964       1 node_affinity.go:72] Evicted 0 pods


4.4 排擠測試節點:
代碼: [選擇]
kubectl drain worker03.localdomain --ignore-daemonsets --delete-local-data  --grace-period=0 --force
kubectl get nodes worker03.localdomain
確認節點狀態類似如下:
NAME                   STATUS                     ROLES    AGE   VERSION
worker03.localdomain   Ready,SchedulingDisabled   <none>   71d   v1.15.0


等待片刻,確認所有 running pods 都只運行在其他 workers 上面:
web-6fc4fb46d-k5pzr              1/1     Running   0          88s     10.47.0.23   worker01.localdomain   <none>           <none>
web-6fc4fb46d-l9h4j              1/1     Running   0          52s     10.39.0.24   worker02.localdomain   <none>           <none>
web-6fc4fb46d-mqwqv              1/1     Running   0          85s     10.47.0.26   worker01.localdomain   <none>           <none>
web-6fc4fb46d-phr8r              1/1     Running   0          71s     10.47.0.8    worker01.localdomain   <none>           <none>
web-6fc4fb46d-t5ct7              1/1     Running   0          80s     10.47.0.27   worker01.localdomain   <none>           <none>
web-6fc4fb46d-vq4mk              1/1     Running   0          5m38s   10.39.0.8    worker02.localdomain   <none>           <none>
web-6fc4fb46d-ww2nq              1/1     Running   0          6m8s    10.47.0.10   worker01.localdomain   <none>           <none>
web-6fc4fb46d-wz8vl              1/1     Running   0          58s     10.39.0.22   worker02.localdomain   <none>           <none>
web-6fc4fb46d-xvk48              1/1     Running   0          5m25s   10.39.0.11   worker02.localdomain   <none>           <none>
web-6fc4fb46d-xxr5q              1/1     Running   0          5m56s   10.47.0.16   worker01.localdomain   <none>           <none>
web-6fc4fb46d-zcg6l              1/1     Running   0          2m29s   10.47.0.18   worker01.localdomain   <none>           <none>
web-6fc4fb46d-zh7zv              1/1     Running   0          11m     10.39.0.19   worker02.localdomain   <none>           <none>
web-6fc4fb46d-zldt7              1/1     Running   0          5m31s   10.39.0.4    worker02.localdomain   <none>           <none>
web-6fc4fb46d-zxrxw              1/1     Running   0          31m     10.39.0.7    worker02.localdomain   <none>           <none>


4.4 將節點復原:
代碼: [選擇]
kubectl uncordon worker03.localdomain
kubectl get nodes
確認所有節點都處於 ready 狀態:
NAME                   STATUS   ROLES    AGE   VERSION
master01.localdomain   Ready    master   71d   v1.15.0
master02.localdomain   Ready    master   71d   v1.15.0
master03.localdomain   Ready    master   71d   v1.15.0
worker01.localdomain   Ready    <none>   71d   v1.15.0
worker02.localdomain   Ready    <none>   71d   v1.15.0
worker03.localdomain   Ready    <none>   71d   v1.15.0


觀察 CronJob 剛有執行最近一次工作:
代碼: [選擇]
kubectl get pods -n kube-system | grep Completed看到類似如下的結果:
descheduler-1564671600-spl42                   0/1     Completed   0          1h
descheduler-1564671900-2sn9j                   0/1     Completed   0          30m
descheduler-1564672200-sq5zw                   0/1     Completed   0          77s


再次檢查 logs:
代碼: [選擇]
kubectl -n kube-system logs descheduler-1564672200-sq5zw將會發現有相當數量的 pods 被 evicted 了:
...
I0801 15:11:00.012104       1 node_affinity.go:72] Evicted 20 pods


確認 pods 被重新分配回節點:
web-6fc4fb46d-n687t              1/1     Running   0          87s     10.42.0.17   worker03.localdomain   <none>           <none>
web-6fc4fb46d-nzdrs              1/1     Running   0          91s     10.42.0.16   worker03.localdomain   <none>           <none>
web-6fc4fb46d-qrn6n              1/1     Running   0          2m8s    10.47.0.14   worker01.localdomain   <none>           <none>
web-6fc4fb46d-qxd8v              1/1     Running   0          2m1s    10.39.0.15   worker02.localdomain   <none>           <none>
web-6fc4fb46d-rpw8b              1/1     Running   0          70s     10.42.0.11   worker03.localdomain   <none>           <none>
web-6fc4fb46d-rxxrn              1/1     Running   0          2m3s    10.47.0.19   worker01.localdomain   <none>           <none>
web-6fc4fb46d-svts8              1/1     Running   0          2m6s    10.47.0.15   worker01.localdomain   <none>           <none>
web-6fc4fb46d-v9q9c              1/1     Running   0          2m4s    10.47.0.17   worker01.localdomain   <none>           <none>
web-6fc4fb46d-x5vrs              1/1     Running   0          110s    10.39.0.21   worker02.localdomain   <none>           <none>
web-6fc4fb46d-xfrnh              1/1     Running   0          76s     10.42.0.8    worker03.localdomain   <none>           <none>
web-6fc4fb46d-xmz64              1/1     Running   0          7m11s   10.42.0.4    worker03.localdomain   <none>           <none>
web-6fc4fb46d-z2xhw              1/1     Running   0          7m9s    10.42.0.7    worker03.localdomain   <none>           <none>
web-6fc4fb46d-zkv95              1/1     Running   0          7m12s   10.42.0.2    worker03.localdomain   <none>           <none>
web-6fc4fb46d-zltxl              1/1     Running   0          105s    10.47.0.6    worker01.localdomain   <none>           <none>



五,結論

透過 DeScheduler 我們可以實現動態的服務應用自動化配置,將負載平均到所有的 worker 節點,可確保 cluster 資源消費的合理化,有助於提升容錯性與服務穩定性。值得一試。

24
Building a K8S load balancer yourself

v1.0
2019-07-30


一、前言

看網絡上許多關於 K8S 的文章,談到服務(Service)導出方法的時候,若不想手動操作 expose 或使用 NodePort 的話,其中有一個選項是 LoadBalancer。聽起來是非常 cool 的方式,可惜大部分都是雲端服務商才能提供的服務。這對於一般入門者來說,消費雲端服務是一項奢侈品項,或是單純練習並想花那些成本。

然而,對於成功自架 K8S Cluster 的朋友來說,可以安裝 MetalLB 這個產品提供 local 的負載平衡器,實在是一大福音!


二、安裝步驟

2.1 直接用 kubectl 部署:
kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml

成功的話,會多出一個 metallb-system 的 name space,裏面會運行如下兩種 pod:
代碼: [選擇]
controller
speaker

2.2 配置 ConfigMap
請以文字編輯器編輯一份 yaml (metallb_configmap.yml),其內容如下:
代碼: [選擇]
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: my-ip-space
      protocol: layer2
      addresses:
      - 192.168.100.240-192.168.100.249

請注意:將 ip range 修改爲設當的網段:可以連線也不會造成 IP 位置衝突即可。

完成後套用 ConfigMap:
kubectl apply -f metallb_configmap.yml

沒錯,就這麼簡單!這樣我們的 MetalLB 就已經設定完成了。


三、測試

如下,我們透過一個簡單的 nginx 服務來測試 LoadBalancer 是否可以運作。

3.1 建立 nginx deployment 設定檔(nginx.yaml),其內容如下:
代碼: [選擇]
apiVersion: v1
kind: Namespace
metadata:
  name: metallb-test
  labels:
    app: metallb
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: metallb-test
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-deployment
  namespace: metallb-test
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  sessionAffinity: None
  type: LoadBalancer

這裏我們獨立建一個 metallb-test 的 name space 以便我們測試用。

3.2 執行部署:
kubeclt apply -f nginx.yaml

3.3 假如部署沒有問題,我們就可以執行如下命令來檢查結果:
kubectl -n metallb-test get svc -o wide

應該看到類似如下這樣的 EXTERNAL-IP :
代碼: [選擇]
NAME               TYPE           CLUSTER-IP       EXTERNAL-IP       PORT(S)        AGE     SELECTOR
nginx-deployment   LoadBalancer   10.103.250.239   192.168.100.240   80:16656/TCP   2m51s   app=nginx

這就代表 MetalLB 這個 LoadBalancer 是可以 work 的!

3.4 清除部署:
kubeclt delete -f nginx.yaml


四、結論
MetalLB 可以說是窮人的 K8S LoadBalancer,設定非常簡單,部署上沒有太高難度。非常適合自架練習 K8S 服務使用。

25
Using Ceph RBD Storage Classes in K8S

Author: netman<netman@study-area.org>
Date: 2019-07-25


一,前言

K8S 中可以使用的 volume 種類非常多,同時也提供 Storage Class 的方式讓管理員更方便的調用定義好的儲存種類。有興趣的話可以參考官方文件:
   https://kubernetes.io/docs/concepts/storage/volumes/
   https://kubernetes.io/docs/concepts/storage/persistent-volumes
   https://kubernetes.io/docs/concepts/storage/storage-classes/

本篇文章僅以簡單的實作形式來說明如何在 K8S 中使用 Ceph RBD 這一儲存資源。


二,前提條件

在展開實作之前,我們假設如下環境已經建置完成並且正常運作中:
Ceph Storage (monitors: 192.168.100.21-23)
K8S Cluster (用 kubeadm 部署)
這裏不再討論如何建置上述系統了,請另行參考其他文章。


三,實作步驟

3.1 於 ceph 上面建立專用的 pool 並設定帳號權限:
代碼: [選擇]
ceph osd pool create kube 32 32    # 具體的 PG number 請根據現況調整
ceph osd pool application enable 'kube' 'rbd'
ceph auth get-or-create client.kube mon 'allow r' osd 'allow class-read object_prefix rbd_children, allow rwx pool=kube'

3.2 記錄如下 base64 編碼值( K8S 設定 secrets 需要一致):
代碼: [選擇]
ceph auth get-key client.admin | base64    # 輸出將對應到 k8s 的 ceph-secret-admin secret
ceph auth get-key client.kube | base64     # 輸出將對應到 k8s 的 ceph-secret-kube secret

3.3 在 k8s cluster 中的 worker nodes 上面安裝 ceph-common, 並將 ceph monitor 中的 admin key 檔案複製過來:
代碼: [選擇]
yum install -y ceph-common
scp 192.168.100.21:/etc/ceph/ceph.client.admin.keyring /etc/ceph/

3.4 在 k8s 的操作主機(已經設定好context並能順利執行kubectl, 同時也能執行git命令)建立一個專用工作目錄:
代碼: [選擇]
mkdir ~/kube-ceph
cd ~/kube-ceph

3.5 建立 secrets yaml:
代碼: [選擇]
cat > kube-ceph-secret.yaml << END
apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret-admin
type: "kubernetes.io/rbd"
data:
  key: QVFEYzF0SmNMaVpkRmhBQWlKbUhNbndaR2tCdldFcThXWDhaaXc9PQ==
---
apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret-kube
type: "kubernetes.io/rbd"
data:
  key: QVFDSFdUaGROcC9LT2hBQUpkVG5XVUpQUOYrZGtvZ2k3S0Zwc0E9PQ==
END

3.6 建立 Storage Class yaml:
代碼: [選擇]
cat > kube-ceph-sc.yaml << END
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: ceph-rbd
#provisionen: kubernetes.io/rbd
provisioner: ceph.com/rbd
parameters:
  monitors: 192.168.100.21:6789,192.168.100.22:6789,192.168.100.23:6789
  adminId: admin
  adminSecretName: ceph-secret-admin
  adminSecretNamespace: default
  pool: kube
  userId: kube
  userSecretName: ceph-secret-kube
  userSecretNamespace: default
  imageFormat: "2"
  imageFeatures: layering
END

3.7 建立 Persistent Volume Claim (PVC) yaml:
代碼: [選擇]
cat > kube-ceph-pvc.yaml << END
metadata:
  name: ceph-k8s-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ceph-rbd
  resources:
    requests:
      storage: 1Gi
END

3.8 因爲透過 kubeadm 部署 k8s 的原因,其內建的 provider 並沒有提供 rbd 的支援(provisioner: kubernetes.io/rbd),會遇到如下 error:
persistentvolume-controller     Warning   ProvisioningFailed  Failed to provision volume with StorageClass "ceph-rbd": failed to create rbd image: executable file not found in $PATH, command output:

我們需要另行下載並部署延伸支援(provisioner: ceph.com/rbd, 上面的 Storage Class yaml 已經修改爲延伸支援了):
代碼: [選擇]
git clone  https://github.com/kubernetes-incubator/external-storage
cd external-storage/ceph/rbd/deploy/rbac/
kubectl apply -f ./

3.9 確認 rbd-provisioner pod 有正常運作:
代碼: [選擇]
kubectl get pods# 確定可以看到類似如下的 pod 在 Running 的狀態:
rbd-provisioner-9b8ffbcc-bwzvr   1/1     Running   0          58s

3.10 套用 ceph rbd 並將 ceph-rbd Storage Class 設定爲 default:
代碼: [選擇]
cd ~/kube-ceph
kubectl apply -f ./
kubectl patch storageclass ceph-rbd -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

3.11 驗收成果
代碼: [選擇]
kubectl get StorageClass# 確認 ceph-rbd 是唯一的 default
NAME                 PROVISIONER    AGE
ceph-rbd (default)   ceph.com/rbd   31s


代碼: [選擇]
kubectl get pvc# 確認 pvc 有正確的 bound 起來
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ceph-k8s-claim   Bound    pvc-00840751-aedf-11e9-8a7d-525400b83b04   1Gi        RWO            ceph-rbd       75s


同時,在 ceph 那邊也能看到新的 rbd image 被自動建立起來:
代碼: [選擇]
rbd list -p kube# 可以看到類似如下的結果:
kubernetes-dynamic-pvc-755378b8-aedf-11e9-984f-16b92f357547

3.12 將 pvc 實作於 pod 內:
代碼: [選擇]
cat > kube-ceph-pod.yaml << END
apiVersion: v1
kind: Pod
metadata:
  name: kube-ceph-pod       
spec:
  containers:
  - name: ceph-busybox
    image: busybox         
    command: ["sleep", "60000"]
    volumeMounts:
    - name: ceph-volume       
      mountPath: /usr/share/ceph-rbd
      readOnly: false
  volumes:
  - name: ceph-volume 
    persistentVolumeClaim:
      claimName: ceph-k8s-claim
END

26
Linux 討論版 / Re: ssh login 認證加密問題
« 於: 2019-07-16 20:38 »
有具體的錯誤訊息或log嗎?

27
Linux 討論版 / Re: dns備援伺服器的設定
« 於: 2019-07-08 21:15 »
named[7962]: zone XXX.edu/IN: loaded serial 158
上面這行就看得到 serial 是 158
或是,簡單些,你修改 master 上面的 record,然後將 dns server 指定 slave 看看是否能看到?

28
firewall?
netstat 看到的 port 是 listen 在 0.0.0.0 上面嗎?

29
Linux 討論版 / Re: 用户组权限
« 於: 2019-07-07 22:20 »
logout 再 login 一次呢?

30
Linux 討論版 / Re: dns備援伺服器的設定
« 於: 2019-07-07 22:18 »
如果 zone 有載入,且 serail 有跟 master 同步,那就是OK了。

頁: [1] 2 3 ... 500