怎麼解fdisk切出來的partition比實際的小

今天跟人要了一批機器,在初始化硬碟的時候遇到了用fdisk切出來的partition比用fdisk -l看的還小很多的情況

花了兩個小時研究終於找到解法,這邊紀錄一下

由於這次要的這批機器是別人用過的機種,在format硬碟的時候遇到了兩個狀況

狀況1: cannot write disk label: Invalid argument

partition的label無法寫入

$ fdisk -l /dev/sdb
Command (m for help): n
Partition number (1-128, default 1):
First sector (34-750157790, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-750157790, default 750157790):
Created partition 1

Command (m for help): w
fdisk: cannot write disk label: Invalid argument

狀況2: 切出來的partition比實際小很多

使用fdisk -l看的時候有1.3TB左右

$ fdisk -l /dev/sdb
WARNING: fdisk GPT support is currently new, and therefore in an experimental phase. Use at your own discretion.

Disk /dev/sdb: 1438.7 GB, 1438679826432 bytes, 2809921536 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: gpt
Disk identifier: 8A5FB6FB-4D7D-4BDC-8BFE-BCE7994F319F

但實際切出來只有300多GB

$ fdisk /dev/sdb
WARNING: fdisk GPT support is currently new, and therefore in an experimental phase. Use at your own discretion.
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n
Partition number (1-128, default 1):
First sector (34-750157790, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-750157790, default 750157790):
Created partition 1


Command (m for help): p

Disk /dev/sdb: 1438.7 GB, 1438679826432 bytes, 2809921536 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: gpt
Disk identifier: 8A5FB6FB-4D7D-4BDC-8BFE-BCE7994F319F


#         Start          End    Size  Type            Name
 1         2048    750157790  357.7G  Linux filesyste

初步猜測是MBR裡面有一些舊資訊妨礙了fdisk

然後上網查了查找到有一個更好用的工具gdisk,可以顯示更多資訊然後幫我們重建

試了一下,去切另一顆1.8TB的硬碟

$ yum install -y gdisk
$ gdisk /dev/sdc
GPT fdisk (gdisk) version 0.8.6

Caution: invalid backup GPT header, but valid main header; regenerating
backup header from main header.

Partition table scan:
  MBR: hybrid
  BSD: not present
  APM: not present
  GPT: damaged

Found valid MBR and corrupt GPT. Which do you want to use? (Using the
GPT MAY permit recovery of GPT data.)
 1 - MBR
 2 - GPT
 3 - Create blank GPT

Your answer: 1

Warning! Secondary partition table overlaps the last partition by
33 blocks!
You will need to delete this partition or resize it in another utility.

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

Command (? for help): n
Partition number (1-128, default 1):
First sector (34-3904896990, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-3904896990, default = 3904896990) or {+-}size{KMGTP}:
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'

Command (? for help): p
Disk /dev/sdc: 3904897024 sectors, 1.8 TiB
Logical sector size: 512 bytes
Disk identifier (GUID): 053E1BA2-8455-4B03-A39D-CDA708C1F8C5
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 3904896990
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048      3904896990   1.8 TiB     8300  Linux filesystem

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdc.
The operation has completed successfully.

$ mkfs.ext4 /dev/sdc1

成功了!!,切出了原本disk的大小

主要多做了一個動作

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

在切partition之前先建立一個新的MBR,就解決了上面的問題

從container內部去跟kubernetes溝通小問題

這一陣子在自己開發kubernetes上的應用程式

這個應用程式需要跟kubernetes master溝通交換資料

通常開發一個跟k8s交換訊息的程式至少需要兩個資訊

  • master endpoint
  • token

token等相關訊息如果有綁定serviceaccount的話,可以從container裡面的/var/run/secrets/kubernetes.io/serviceaccount抓出來

$ cat /var/run/secrets/kubernetes.io/serviceaccount/token

而master的endpoint位置我很自然設定為用cluster-info抓出來的位置

$ kubectl cluster-info
Kubernetes master is running at https://100.84.71.1:6443

但是最近出現一個現象

container啟動過了一段時間之後會出現無法連線到master的現象

$ curl https://100.84.71.1:6443
curl: (7) Couldn't connect to server

這問題我百思不解,怕的是docker內部網路問題
後來參考了其他應用程式是怎麼做的
https://cloud.google.com/solutions/configuring-jenkins-kubernetes-engine

原來k8s內部container要跟k8s溝通得設定https://kubernetes.default

我把master endpoint直接改成https://kubernetes.default就正常了

這邊筆記一下

工程師去日本找工作-高度人才轉永住

來日本也大約三年半左右,就在昨天成功拿到了日本永住權

對自己來說也算是個人生轉捩點,寫篇文紀錄一下

延續30歲工程師去日本找工作這篇

剛來日本的時候其實還沒有想清楚自己會在日本多久

生活了一段時間之後,認識了一些朋友,了解了一些在日本長住的情報

發現想在日本定居對工程師來說並非那麼遙不可及

尤其是買房子這件事,相較於在台北置產在東京都買房似乎是更能看的到一線曙光

之後便下定決心在日本定下來

說到長居日本不外乎兩種手段

  • 五年歸化日本籍
  • 十年換永住

一開始是打算採用歸化的方式的,但是在工作兩年後也就是去年2017

日本開放了高度人才身分1年換永住的超優惠方案

後來我選擇了這個高度人才換永住方案

高度人才的方案可以參考:http://www.immi-moj.go.jp/newimmiact_3/

現在進入正題

高度人才轉永住有兩種

  1. 70分 滿三年換永住
  2. 80分 滿一年換永住

我在2017年前的資歷

  • 5年經驗工程師
  • 年收500萬上下
  • 日檢一級
  • 碩士

換算一下只有65分,在當時資歷是不足以成為高度人才的

想拼一下,2017/06/01時換到了現在的工作,年收大幅提高

高度人才分數超過了80分,也就是我只要待滿一年就可以換永住了

想說順便先把高度人才申請起來,就在十月底的時候申請了高度人才簽證並在2017/11/07時拿到了通過證明跟結果通知書

而到了今年2018/06/01正好滿一年,我在2018/06/13時送出了永住申請書

有一說現在由於申請人數暴增,永住申請變成要等的非常久

我自己上網查,看到在品川入管申請普遍來說現在都要8~12個月

後來聽同事說有個小道消息,我住神奈川可以去橫濱申請,謠傳那邊申請只需要4個月左右就會下來了

就這樣跑去了橫濱申請

永住申請大概可以歸納需要兩大類文件

自身相關的文件

  • 永住許可申請書 1份 : 這個可以去法務省網站下載 : http://www.moj.go.jp/ONLINE/IMMIGRATION/16-4.html
  • 三個月內4cmx3cm照片 一張: 這個去車站附近或是去入管局現場找拍照的地方拍就好
  • 包含全戶的住民票 一張: 這可現在可以直接去便利商店用mynumber那張卡印出來
  • 在職證明書 一張: 請公司開
  • 年收證明書 一張: 請公司開
  • 納稅證明(納税証明書)一份: 這個要去居住地的區役所申請,因為我是80分資格所以只申請了"最近一年"的納稅證明就行了,其他的話要三年
  • 銀行帳簿的影本(預貯金通帳の写し): 我自己是印了近半年的出入帳紀錄
  • 護照正本: 申請時提示用
  • 永住申請理由書 一張
  • 在留卡: 申請時提示用
  • 高度人才申請時的所有資料: 申請高度人才需要繳什麼 這邊就準備什麼

這邊花了我比較多時間的是高度人才申請資料,因為我得向在台灣時的公司還有學校申請退職證明跟畢業證書

當時沒想太多只申請了一份,在準備時發現還要在丟一份一樣的,所以又花了些時間在申請一次

在來就是不知到永住申請理由書怎麼寫,後來是直接上網拷貝了別人的範本來改

範本如下

保證人相關的文件

  • 身元保証書 一份: 可以去法務省網站下載: http://www.moj.go.jp/ONLINE/IMMIGRATION/16-4.html
  • 保證人印章: 用來蓋上面的申請書用 蓋完就可以還回去了
  • 保證人的在職證明
  • 保證人的納稅證明
  • 保證人的住民票

看了上面可以發現,其實最難的是找保證人,因為要一堆資料而且又是隱密資料

雖說永住申請的保證人不用擔什麼法律責任,但一般人不知道的話大概都不太敢給

而保證人可以是

  • 日本人
  • 永住者

我是找了一個有永住的中國人同事當我的保證人

在送件之後上網查了各種資料

入管局統計網站看,發現永住退件率將近一半

也就是每兩個人申請就有一個人被拒絕,這倒是讓我有點嚇到

查了一下會被退件的幾個理由

  • 收入太低(一說是300萬)
  • 扶養報太多
  • 有交通違規
  • 繳稅有遲繳

我自己是不開車,然後扶養父母這樣的條件去申請

工程師來講如果進入有規模的企業,理論上不會有收入跟繳稅的問題

唯一擔心的是我在2017年有接副業,雖然副業有正常報稅還是擔心有影響

不過好在最後還是過了

在2018/08/25的時候我收到了要求補件的通知書,說希望我補繳申請高度人才時收到的通知書

收到之後我在2018/08/27用補件通知書附贈的信封袋回送回去

調查了一下在補件之後有很高的機率在兩個月內會收到結果

在一個半月後的2018/10/03 我收到了永住通過的明信片

申請這段時間真的是每天都很擔心,不自覺得跑去開信箱

當下真是覺得心中放下了一塊大石頭

現在日本永住拿到了,也算完成了一個人生目標

最後補一下整段歷程作個總結

  • 2015/03/15 進入日本工作
  • 2017/06/01 換工作拿到80點的高度人才資格
  • 2017/11/07 拿到高度人才簽
  • 2018/06/13 橫濱申請永住
  • 2018/10/03 拿到永住簽證

在橫濱申請永住花了大概3個月又3週左右,感謝當初分享情報的那位同事

5分鐘試作一個最簡單的airflow plugin

因為想要讓我的使用者去可以更容易的跟既有的平台做排程工作

最近想試著製作airflow的operator

參考了一下官方網站:https://airflow.apache.org/plugins.html

airflow本身提供了operator, menu_link, hook等等的接口

照著官方網站,簡單試做了一個簡單版的myoperator plugin

要製作自己的plugin方法很單純

去plugin目錄下塞自己的python檔就好了

假設我做了一個plugin檔案$AIRFLOW_HOMR/plugins/my.py

內容如下

from airflow.plugins_manager import AirflowPlugin
from airflow.models import BaseOperator
from airflow.utils.decorators import apply_defaults


class MyOperator(BaseOperator):
    @apply_defaults
    def __init__(self,
                 message,
                 *args, **kwargs):
        super(MyOperator, self).__init__(*args, **kwargs)
        self.message = message

    def execute(self, context):
        print("Message:[%s]" % self.message)

    def on_kill(self):
        print("Killed MyOperator")


# Defining the plugin class

class AirflowTestPlugin(AirflowPlugin):
    name = "myplugin"
    operators = [MyOperator]

這邊重點是要製作一個class去繼承AirflowPlugin

他宣告了這個python檔要涵蓋哪些type的plugin跟這個plugin的名字

name這個屬性會影響之後要import時候的路徑,官方說明如下

from airflow.{type, like "operators", "sensors"}.{name specificed inside the plugin class} import *

因為我這邊只想做一個myoperator,所以只做了一個MyOperator去繼承BaseOperator

當實做一個Operator的時候有兩個要點

  1. 使用@apply_defaults去包住__init__然後用super去傳遞初始化參數
  2. 實作execute的內容

參考:https://github.com/apache/incubator-airflow/blob/master/airflow/models.py

一個Operator可以覆寫的函式有

  • pre_execute
  • execute
  • post_execute
  • on_kill

可以照自己的需求去實作

之後只要重啟airflow的webserver/scheduler/worker等就行了

這邊再給一個範例dag $AIRFLOW_HOMR/dags/hello_world.py

from datetime import datetime
from airflow import DAG
from airflow.operators.dummy_operator import DummyOperator
from airflow.operators.python_operator import PythonOperator
from airflow.operators.bash_operator import BashOperator

from airflow.operators.myplugin import MyOperator

def print_hello():
    return 'Hello world!'

dag = DAG('hello_world', description='Simple tutorial DAG',
          schedule_interval='10 * * * *',
          start_date=datetime(2017, 3, 20), catchup=False)

dummy_operator = MyOperator(task_id='dummy_task', message="Hello World", dag=dag)

hello_operator = PythonOperator(task_id='hello_task', python_callable=print_hello, dag=dag)

t1 = BashOperator(
    task_id='print_date',
    bash_command='date',
    dag=dag)


dummy_operator >> hello_operator >> t1

這邊的重點就只有import的方式

我用from airflow.operators.myplugin import MyOperator去import自己做的MyOperator

當初一直不知道怎麼import才正確,因為一些古早範例都是寫from airflow.operators import xxxx

讓我卡了一小段時間

.....

題外話之前把airflow從1.8升級到1.10之後遇到timezone被鎖死在UTC的狀況

現階段只能用降版回1.8的方式解決

這幾天airflow試用下來他的好處我還沒體會到他的坑倒是踩了不少

現在想想自己還是習慣用Azkaban

但是客戶想用airflow,也只能硬著頭皮去踩坑

sub_filter: 讓Nginx去代理含絕對路徑的服務

最近再研究怎麼讓nginx透過subpath去代理一個本身是用絕對路徑當連結的服務

一般來說設計好使用相對路徑的服務,我都可以簡單使用nginx的一個subpath去代理

location /myapp/ {
  rewrite ^/mysapp/(.*)$ /$1 break;
  proxy_pass http://myapp;
  proxy_redirect http://myapp/ $scheme://$host/myapp/;
}

但是有些設計成使用絕對路徑的像是hue/airflow等等就會造成路徑混亂的情況

比如說的myapp裡面有個link是/myresource 我希望點擊以後會轉到/myapp/myresource

但是很不幸地直接點擊的結果他最終是導向/myresource

而新版的Nginx有個module叫做ngx_http_sub_module

他提供一個function叫sub_filter可以替換掉source file的字串

這讓像是hue/airflow等服務被nginx用subpath代理提供了一個方案

下面是我用nginx去代理airflow的範例

location /airflow/ {
  rewrite ^/airflow/(.*)$ /$1 break;
  proxy_pass http://my-airflow;
  proxy_redirect http://my-airflow/admin $scheme://$host/airflow/admin;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
 
  proxy_set_header Accept-Encoding "";
  sub_filter_once off;
  sub_filter_types *;
  sub_filter   \"/static \"airflow/static;
  sub_filter   \"/admin \"/airflow/admin;
}

裡面比較重要的設定如下

  • proxy_set_header Accept-Encoding: 這邊設定為空,避免gzip等編碼讓sub_filter失效
  • sub_filter_once: 設定成off 可以替代掉多個字串
  • sub_filter_types: 設定成* 讓js, css等檔案也能適用
  • sub_filter: 要取代的字串 這邊讓絕對路徑的字串都加上nginx的subpath

算是有點弔詭的方案,不過目前用它成功代理了以前很多subpath會出問題的服務

這邊紀錄一下

Airflow CeleryExecutor 無法啟動的問題

這幾天要替部門設定scheduler

原本習慣用azkaban的,但是因應需求這次想要用airflow給部門用

於是初次嘗試設置了airflow,一試即採坑

照著網路上的說明

設置了airflow/postgresql/redis的all in one配置

https://analytics.livesense.co.jp/entry/2018/02/06/132842

一步安裝Library

apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E1DD270288B4E6030699E45FA1715D88E1DF1F24 \
    && su -c "echo 'deb http://ppa.launchpad.net/git-core/ppa/ubuntu trusty main' > /etc/apt/sources.list.d/git.list" \
    && apt-get update \
    && apt-get install -y python python-pip build-essential autoconf libtool pkg-config python-opengl python-imaging python-pyrex python-pyside.qtopengl idle-python2.7 qt4-dev-tools qt4-designer libqtgui4 libqtcore4 libqt4-xml libqt4-test libqt4-script libqt4-network libqt4-dbus python-qt4 python-qt4-gl libgle3 python-dev libssl-dev curl wget vim procps redis-server \
    && pip install Cython \
    && pip install pytz \
    && pip install pyOpenSSL \
    && pip install ndg-httpsclient \
    && pip install pyasn1 \
    && SLUGIFY_USES_TEXT_UNIDECODE=yes pip install apache-airflow[crypto,celery,postgres,hive,jdbc,redis]==1.10.0 \
    && pip install celery \
    && pip install psycopg2-binary

啟動redis

redis-server &

設置airflow使用CeleryExecutor,使用postgresql當db跟redis當queue

...
executor = CeleryExecutor
...
sql_alchemy_conn = postgresql://airflow:airflow@localhost:5432/airflow
...
broker_url = redis://localhost:6379/0
...
result_backend = db+postgresql://airflow:airflow@localhost:5432/airflow
...

初始化並啟動各元件

$ airflow initdb
$ airflow webserver -D 
$ airflow flower -D 
$ airflow scheduler -D
$ airflow worker -D

設定好之後很奇怪的是trigger各種job永遠都是Running的狀態

永遠不會結束

後來登入flower http://localhost:5555

並沒有看到任何worker的存在

我百思不解

後來參考https://qiita.com/xecus/items/9722b287cc6aee4083ae

做了簡單的celery flower跟worker的測試

理論上有了worker,flower就要能看到才對

後來檢查了worker的訊息

出現了一些奇怪的訊息

後來是透過設置C_FORCE_ROOT強制啟動了worker

$ export C_FORCE_ROOT="true"
$ airflow worker -D

https://stackoverflow.com/questions/20346851/running-celery-as-root

姑且先解除了Job總是Running的問題

這邊紀錄一下

Nginx Ingress Reload的坑

最近在設計把Jupyter放在k8s上給多個人使用的應用

遇到了一個問題,就是Jupyter的terminal介面會時不時的斷掉

正個在以前standalone server時代沒發生過的

去追蹤Jupyter的log

...
[I 07:37:41.135 NotebookApp] New terminal with automatic name: 5
TermSocket.open: 5
TermSocket.open: Opened 5
Websocket closed

Websocket的被close掉了,嗯?為什麼k8s上會發生這現象

後來回想了一下我Jupter的連接方式

Pod  <-  Service <- Ingress <- client

我多用了一個Nginx Ingress夾在client跟service中間,猜測應該是Nginx Ingress的問題

把Nginx Ingress移除掉之後就一切正常了

可是為什麼Nginx Ingress會讓我的websocket connection斷掉

用下面指令查詢了一下log

$ kubectl logs -f nginx-ingress-controller-676fbd589f-xxxx -n ingress-nginx

看到了nginx backend reload的訊息

I0715 03:15:14.094602       9 controller.go:169] Configuration changes detected, backend reload required.
I0715 03:15:14.274555       9 controller.go:179] Backend successfully reloaded.

後來調查了一下nginx -s reload這樣一個動作,他雖能保證service不中斷

卻不能保證websocket的冗余,nginx是用master跟worker process的方式分工

nginx所謂的reload,開啟新的worker然後shutdown舊的worker,所以像websocket這種必需一直連接的服務就會有中斷現象

但是為什麼會觸發reload呢,我的nginx ingress會分享給很多的service

每當新ingress的被deploy了,就會觸發nginx ingress reload,進而造成websocket的中斷

有沒有什麼解決方法呢,上網找了一下,發現不少人也有遇過類似的問題

進而找到了--enable-dynamic-configuration這個設定

很高興地給他設定下去,結果

I0714 04:45:26.814482       7 controller.go:169] Configuration changes detected, backend reload required.
I0714 04:45:26.933102       7 controller.go:179] Backend successfully reloaded.
I0714 04:45:26.934808       7 controller.go:196] Dynamic reconfiguration succeeded.

沒用啊,還是觸發了backend reload

一路往下追source code

要不觸發backend reload必需是

n.cfg.DynamicConfigurationEnabled && n.IsDynamicConfigurationEnough(pcfg)

--enable-dynamic-configuration只會影響DynamicConfigurationEnabled

IsDynamicConfigurationEnough又是什麼

func (n *NGINXController) IsDynamicConfigurationEnough(pcfg *ingress.Configuration) bool {
    copyOfRunningConfig := *n.runningConfig
    copyOfPcfg := *pcfg

    copyOfRunningConfig.Backends = []*ingress.Backend{}
    copyOfPcfg.Backends = []*ingress.Backend{}

    return copyOfRunningConfig.Equal(&copyOfPcfg)
}

測了一下只有在是backend更新(增加instance, 修改deployment等)的情況下才能不觸發backend reload

而我是deploy新的ingress,所以他必定會觸發reload

這下可麻煩了

所幸找到了可worker-shutdown-timeout這個設定

使用configmap加到nginx ingress裡面

---

kind: ConfigMap

apiVersion: v1

metadata:

  name: nginx-configuration

  namespace: ingress-nginx

  labels:

    app: ingress-nginx

data:

  worker-shutdown-timeout: 3600s

worker-shutdown-timeout,這個設定可以延遲nginx worker被砍掉

nginx ingress預設是10s,所以目前看到issue report都是說約10秒後會被砍掉

但是worker-shutdown-timeout也不能設定太長,舊的process活太長會有OOM的風險

搭配Pain(less) NGINX Ingress

歸納個總結

在目前nginx不支援dynamic reload的情況下

想要在k8s上做nginx ingress給多個服務共享幾個原則

  • 盡量減少新增修改ingress機會
  • 盡量每個namespace都能配上一個ingress controller來減少不同namepsace之間互相干擾
  • 設定worker-shutdown-timeout來降低nginx backend reload的直接影響

以上

docker stats 跟 RSS的差距

今天用戶回報,他觀看memory usage的時候

發現使用docker stats指令看得使用量跟實際用ps aux看到的使用量有很大的差距

使用ps指令觀看RSS記憶體使用量

$ docker exec  my-app ps -o rss,vsz,sz 1
  RSS    VSZ    SZ
945120 23754744 5938686

RSS是物理記憶體使用量,當初設定記憶體監控的時候是以這個為準

可是登上server的時候使用docker指令去看卻差了很多

docker stats my-app
CONTAINER           CPU %               MEM USAGE / LIMIT   MEM %               NET I/O             BLOCK I/O           PIDS
my-app        14.02%              1.965GiB / 5GiB     33.31%              0B / 0B             8.25MB / 50.1MB     276

使用ps指令看到的只有900多MB,使用docker指令看卻有1.96GiB

上網收尋了一下資料

查到了

Note: On Linux, the Docker CLI reports memory usage by subtracting page cache usage from the total memory usage. The API does not perform such a calculation but rather provides the total memory usage and the amount from the page cache so that clients can use the data as needed.

使用docker stats的時候,顯示的是RSS+Cache的使用量

想要看詳細記憶體使用量可以用下面的指令

cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.stat
cache 1203441664
rss 938504192
rss_huge 0
mapped_file 4300800
swap 0
pgpgin 4679655
pgpgout 4156719
pgfault 99018704
pgmajfault 388
inactive_anon 4096
active_anon 938471424
inactive_file 799027200
active_file 404389888
unevictable 0
hierarchical_memory_limit 5368709120
hierarchical_memsw_limit 10737418240
total_cache 1203441664
total_rss 938504192
total_rss_huge 0
total_mapped_file 4300800
total_swap 0
total_pgpgin 4679655
total_pgpgout 4156719
total_pgfault 99018704
total_pgmajfault 388
total_inactive_anon 4096
total_active_anon 938471424
total_inactive_file 799027200
total_active_file 404389888
total_unevictable 0

這會影響的是如果我設定docker container的memory limit的時候,必須考慮RSS+Cache的使用量才行

有個方法可以手動的清掉cache

$ free && sync && echo 3 > /proc/sys/vm/drop_caches && free

用上面的指令可以暫時舒緩container的記憶體使用

這邊做個紀錄

在k8s啟用rstudio的時候遇到302轉址的問題

研究k8s也有一段時間了,今天想從k8s上起一個rstudio搭配nginx controller來用用

當我把ingress的path設定成/rstudio的時候,如果我存取http://LB_URL/rstudio

他會回傳一個302 redirect轉址請求把我轉到http://LB_URL/auth-sign-in

原先設定的path跑掉了而出現404錯誤

ingress設定如下

{
  "kind": "Ingress",
  "apiVersion": "extensions/v1beta1",
  "metadata": {
    "annotations": {
      "kubernetes.io/ingress.class": "nginx",
      "nginx.ingress.kubernetes.io/rewrite-target": "/"  
    }
  },
  "spec": {
    "rules": [
      {
        "host": "LB_HOST",
        "http": {
          "paths": [
            {
              "path": "/rstudio",
              "backend": {
                "serviceName": "rstudio",
                "servicePort": 8787
              }
            }
          ]
        }
      }
    ]
  }
}

後來研究了一下這應該是nginx在轉發的時候出的問題

當有設定proxy_set_header Host xxxx的時候,redirect的對象會主動被改成xxxxx

所以需要新增proxy_redirect的設定把他轉回來

以前我在localhost設定nginx的時候設定如下

    location /rstudio/ {
      rewrite ^/rstudio/(.*)$ /$1 break;
      proxy_pass http://localhost:8787;
      proxy_redirect http://localhost:8787/ $scheme://$host/rstudio/;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }

那要怎麼在nginx-controller增加proxy_redirect的設定呢

查了一下官網有nginx.ingress.kubernetes.io/proxy-redirect-fromnginx.ingress.kubernetes.io/proxy-redirect-to可以用

又nginx controller在設定proxy的時候會自動新增一行proxy_set_header Host $best_http_host
得把proxy_redirect的對象改成$best_http_host

查看nginx controller config的方法如下

#查詢nginx controller的pod container名字
$ kubectl get pod -n ingress-nginx

#進入container
$ kubectl exec nginx-ingress-controller-xxxx -n ingress-nginx -i -t -- bash 

#查看config
$ cat etc/nginx/nginx.conf

修改過後的ingress設定如下

{
  "kind": "Ingress",
  "apiVersion": "extensions/v1beta1",
  "metadata": {
    "annotations": {
      "kubernetes.io/ingress.class": "nginx",
      "nginx.ingress.kubernetes.io/proxy-redirect-from": "http://$best_http_host/",
      "nginx.ingress.kubernetes.io/proxy-redirect-to": "$scheme://$host/rstudio/",
      "nginx.ingress.kubernetes.io/rewrite-target": "/"  
    }
  },
  "spec": {
    "rules": [
      {
        "host": "LB_HOST",
        "http": {
          "paths": [
            {
              "path": "/rstudio",
              "backend": {
                "serviceName": "rstudio",
                "servicePort": 8787
              }
            }
          ]
        }
      }
    ]
  }
}
            

這邊做個紀錄

讓nginx-controller使用external 80 port

在寫k8s使用nginx-controller的時候出現404這篇文章的時候

當時使用了NodePort去當Nginx-Controller的endpoint

設定檔如下

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
  selector:
    app: ingress-nginx

這樣有個問題,就是NodePort會隨機選一個port當做Nginx-Controller的出口

這樣一來每次restart就會不知道是什麼port

雖然我可以直接設定NodePort為80 port,但是k8s port range預設範圍是30000~32767

沒辦法指定80 port當作node port的設定

後來重新去看了官方文件,可以直接把type: NodePort改成type: LoadBalancer

這樣一來預設出口就是80 port了

檢查一下controller的endpoint

$ kubectl describe svc ingress-nginx -n ingress-nginx
Name:                     ingress-nginx
Namespace:                ingress-nginx
Labels:                   <none>
Annotations:              <none>
Selector:                 app=ingress-nginx
Type:                     LoadBalancer
IP:                       10.110.43.7
Port:                     http  80/TCP
TargetPort:               80/TCP
NodePort:                 http  31144/TCP
Endpoints:                10.46.0.6:80
Port:                     https  443/TCP
TargetPort:               443/TCP
NodePort:                 https  30474/TCP
Endpoints:                10.46.0.6:443
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

哎呀,拿到的IP是一個k8s的內部的IP,如次一來外面就無法存取了

後來查了一下可以替他設定externalIP,當作endpoint

修改了一下Nginx-Controller的endpoint設定

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
spec:
  type: LoadBalancer
  externalIPs:
  - 你的external IP or VIP
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
  selector:
    app: ingress-nginx

在重新檢查一下controller的endpoint

$ kubectl describe svc ingress-nginx -n ingress-nginx
Name:                     ingress-nginx
Namespace:                ingress-nginx
Labels:                   <none>
Annotations:              <none>
Selector:                 app=ingress-nginx
Type:                     LoadBalancer
IP:                       10.110.43.7
External IPs:             xxx.xxx.xxx.xxx
Port:                     http  80/TCP
TargetPort:               80/TCP
NodePort:                 http  31144/TCP
Endpoints:                10.46.0.6:80
Port:                     https  443/TCP
TargetPort:               443/TCP
NodePort:                 https  30474/TCP
Endpoints:                10.46.0.6:443
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

多了一個External IPs的設定

將service type改成LoadBalancer,然後設定externalIPs就可以讓Nginx-Controller使用external 80 port了

今天玩了一下這設定,總算有比較清楚service設定LoadBalancer的效果