2019年6月14日 星期五

docker compose 在重開機之後無法啟動

docker compose 在重開機之後無法啟動.md

今天在試時 docker compose 發現host 重開機之後,下指令啟動,但卻無法啟動。

C:\web>docker-compose.exe start
Starting proxy      ... error
Starting site1      ... error
Starting site2      ... error

ERROR: for proxy  Cannot start service proxy: network 02fda54dd66e8782205ee417e901b198279abd40f74b2ffd970fcabc336db8eb not found
ERROR: No containers to start

看起來是找不到network。 真是見鬼了,用network ls 一看,真的不見了。

C:\web>docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
202191da323c        nat                 nat                 local
6f2b7ad221fe        none                null                local

後來才想起來 windows server 2019 重開機之後不會保留 driver 為 nat 的 network。
另一個悲傷的故事

既然 start 的指令無法啟動,那 up 指令會怎樣呢?

C:\web>docker-compose.exe up -d
Creating network "web_lan" with driver "nat"
Starting proxy ... error

ERROR: for proxy  Cannot start service proxy: network 02fda54dd66e8782205ee417e901b198279abd40f74b2ffd970fcabc336db8eb not found

ERROR: Encountered errors while bringing up the project.

看到第一行輸出時,心裡還 “耶” 了一下,結果第二行就…

這個也很奇怪,明明network建起來了,但是找不到??? 一整個黑人問號
用network ls看,還真的有建起來

C:\web>docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
88d33743ebc0        web_lan             nat                 local
202191da323c        nat                 nat                 local
6f2b7ad221fe        none                null                local

仔細一看network id ,原來不一樣了。 哇哩!! 新建的network id不一樣, 但是docker不會自動使用新的但是同名的network!!!

那…全部刪掉再建總可以了吧!!

docker-compose down
docker-compose up -d

總算建起來了。
但是只能這樣解嗎? 底下是我的 docker-compose.yml

version: '3.7'

services:
 proxy:
  image : proxy
  container_name: proxy
  restart: always
  networks:
   lan: 
  ports:
   - "80:80"

 site1:
  image : web
  container_name: site1
  ports:
   - "8000:80"
  networks:
   lan:
  depends_on:
   - "proxy"
  restart: always
 site2:
  image : web
  container_name: site2
  ports:
   - "8001:80"
  networks:
   lan:
  depends_on:
   - "proxy"
  restart: always 
networks:
 lan:
  driver: nat

lan 這個network是跟著docker compose一起建起來的。 那不要一起建,先在外面建好總可以吧!!
底下是修改過的 docker-compose.yml

version: '3.7'

services:
 proxy:
  image : proxy
  container_name: proxy
  restart: always
  networks:
   lan: 
  ports:
   - "80:80"

 site1:
  image : web
  container_name: site1
  ports:
   - "8000:80"
  networks:
   lan:
  depends_on:
   - "proxy"
  restart: always
 site2:
  image : web
  container_name: site2
  ports:
   - "8001:80"
  networks:
   lan:
  depends_on:
   - "proxy"
  restart: always 
networks: 
 lan: 
  external: 
   name: nat

建立一個network 叫lan,連結到外部現有的network叫 “nat” 。

#新建時就不會建立新的network
C:\web>docker-compose up -d
Creating proxy      ... done
Creating site1      ... done
Creating site2      ... done

#移除時,docker會發現是外部的network然後就略過
C:\web>docker-compose down
Removing site2      ... done
Removing site1      ... done
Removing proxy      ... done
Network nat is external, skipping

在windows server 2019上使用 docker 建立 driver 為 nat 的 network 重開機之後會消失

在windows server 2019上使用 docker 建立 driver 為 nat 的 network 重開機之後會消失

一開始我以為我發現了一個 windows server 2019 (1809) 的BUG 。

docker create network -d nat mynet

用上面的指令 在docker create network driver 用 nat 的話 ,重開機後,mynet就不見惹。

2018/12 月在 github 就有人 report 這個issue , 但是一直沒修。 https://github.com/docker/for-win/issues/3076

再深入追查才發現這是微軟預設的行為… 我的老天鵝啊!!! 這不合理吧!!!

NAT networks created on Windows Server 2019 (or above) are no longer persisted after reboot.

https://docs.microsoft.com/en-us/virtualization/windowscontainers/container-networking/network-drivers-topologies

並沒有解釋為什麼~~~ 啊啊啊!!! (請允許我內心的哀嚎) 這樣的預設設定不是自癈武功嗎??

山不轉路轉

每次重開機重建network 總行了吧!!

用下面的powershell script 用工作排程器在開機時執行

$networkName = "mylan"
$ErrorActionPreference = "silentlycontinue"
$inspectResult = & docker network inspect $networkName
$ErrorActionPreference = "continue"
#如果network 不存在就建一個新的
if($LASTEXITCODE -eq 1) {
  docker network create -d nat --subnet 192.168.1.0/24 -o com.docker.network.windowsshim.networkname=Docker-$networkName $networkName
} 

哀嚎加演場

後來測試,建立新的network 然後 driver 用 transparent

docker create network -d transparent mynet

一樣會不見!! 我本來己經準備在臉上寫一個慘字了。

還好做完 windows update , network driver 是 transparent 就不會在重開機之後不見了。 應該是 KB4497934KB4494441 其中之一修好的。
windows update for server 2019

但是我在KB的更新說明裡面找不到相關的說明,算了,反正有修就好。

docker for windows 的 volume 無法掛載網路磁碟機

docker for windows 的 volume 無法掛載網路磁碟機

在windows container怎樣把網路磁碟機掛成 Volume, 試了很久。 包括 net use 成一個碟碟機之後再試了就是掛不進去。
google 很久找到的 solution 都是 for linux 的. 在 windows 上要把網路上的磁碟機掛成 volume 似乎就只有類似像 iSCSI 這種方式而己。

山不轉路轉

後來突然轉念, 直接在 container 裡掛起來就好了啊

在container裡下

net use z: "\\172.16.0.10\folder" /user:eric mypassword

還可以再把網路磁碟機變成C槽的某個資料夾

mklink /d z:\ c:\files

2019年6月10日 星期一

WordPress的效能改善

WordPress的效能改善

先說結論

  1. 把PHP的版本升到最新版

  2. 修改 wp-config.php
    把原本

/** MySQL hostname */  
define( 'DB_HOST', 'localhost' );

改成

/** MySQL hostname */  
define( 'DB_HOST', '127.0.0.1' );
  1. 使用page cache 的 plugin 。(我是用 Cache Enabler ,應該是還有其他的選擇)

故事是這樣的

最近要把官網改版,然後使用wordpress來製作,這樣可以讓不懂程式的相關人員可以自己更動網站內容。

BUT ,代誌不是憨人想的那麼簡單

網站快上線時才發現,天啊!! 怎麼這麼慢。 Waiting TTFB (Time To First Byte) 居然要超過4秒。整個網頁跑完十多秒過去了。

於是開始神農嘗百草的日子,先是找到把PHP 從 5.6 升到 7.3 可以縮短約 2000 ms 。 把我們使用的 wordpress 樣版升到最新版本,也有快一點點縮短約500ms 。

現在 TTFB 來到約 2500 ms,還是太慢了。 再來試過很多方法,例如,開啟PHP的opcache , 加大PHP的可用記憶體(memory_limit) 都沒什麼作用。

弄很久才終於找到,把wp-config.php 裡mysql的位址從 localhost 改成 127.0.0.1 馬上縮短1000個ms。 為什麼有效的原因是,因為改成用 IP 之後 ,不需要作內部的 DNS 解析。

再加上wordpress 的 cache plugin,我是用 Cache Enabler 可以讓同一個page 的第二次 request 縮短約 1000ms。

現在首頁在有cache 的狀況下,TTFB大約在20-70ms。算還可以,網站就先這樣上線了。

2019年6月4日 星期二

在IIS 上 CSS,圖片,JS 這幾種類型的檔案, 突然出現 500 INTERNAL SERVER ERROR

在IIS 上 CSS,圖片,JS 這幾種類型的檔案, 突然出現 500 INTERNAL SERVER ERROR

今天在主要對外的網站收到想要讓使用者下載 apk 檔的需求,我想說一塊蛋榚,找一下apk 的MIME Type

application/vnd.android.package-archive

就直接把這個設定加到IIS上電腦層級的MIME Type 設定,然後就去忙別的事了。

沒多久就有人開始反應,全部網站的STYLE全跑掉了。 用開發者工具一看,天啊!! 所有的CSS , 圖片,跟javascript 檔全都回應狀態500。

一開始重啟IIS…沒效,重開機…沒效。 後來突然想到是不是我動了設定的關係,就把剛剛加的MIMETYPE 刪掉… 就好了!!

問一下Google 大神原來還不少人有遇過一樣的症頭。
解法就是改成在 web.config設定, 加入MIMETYPE前,先移掉該type。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <staticContent>
            <remove fileExtension=".apk" />
            <mimeMap fileExtension=".apk" mimeType="application/vnd.android.package-archive" />
        </staticContent>
    </system.webServer>
</configuration>

2019年5月16日 星期四

Docker container 重新啟動之後IP 會改變

Docker container 重新啟動之後IP 會改變

Docker container 重新啟動之後IP 會改變

如果container run在同一個network之下,而且要互通,像下面m1,m2這2個container這樣

docker run -d --net my-net --name m1 myimg
docker run -d --net my-net --name m2 myimg

一開始是可以從 m1 ping(連)的到m2

docker exec -i m1 cmd /c ping m2

Ping m2 [172.20.3.101] (使用 32 位元組的資料):
回覆自 172.20.3.101: 位元組=32 時間=1ms TTL=52

m2 重啟後

docker stop m2
docker start m2

就ping不到m2了

docker exec -i m1 cmd /c ping m2

Ping m2 [172.20.3.101] (使用 32 位元組的資料):
要求等候逾時。

經過數個小時的奮鬥(我的青春啊), 才發現原來每次container重啟IP就會變
而且在m1這台container裡,記的m2還是舊的ip,不會自動更新IP跟名稱對應。

所以,只要讓container的ip固定就好了

docker run -d --net my-net --ip 172.20.3.100 --name m1 myimg
docker run -d --net my-net --ip 172.20.3.101 --name m2 myimg

青春的血淚史…給跟我一樣是新手的你

2019年5月15日 星期三

設定 Nexus Repository OSS 3.X for Windows 啟用HTTPS(使用自我簽署憑證)

設定 Nexus Repository OSS 3.X for Windows 啟用HTTPS(使用自我簽署憑證)

需求

原始的需求只是要在內部環境中架設 Nexus Repository 作 docker private repository 但是 預設要使用IP連線還要加上 port 真的是又臭又長。

所以才會想要設定 Nexus Repository 讓他可以使用 https ,減少 docker image 在tag時太長,字要打很多很累的困擾。

例如,原本的指令

docker tag myimg 172.16.3.100:8000/myimg 

設定完之後只要

docker tag myimg docker.local/myimg 

可以少打很多字, 嗯…果然科技來自於惰性。

想法

利用電腦名稱取代ip (這裡用docker.local 為例; 把要當Repository的電腦取名叫 docker, 就可以用 docker.local 連的到)
而且因為docker client 預設是使用https 也就是443port 做為連線. 如果要儘量縮短網址讓 private repository 使用https連線是最好的做法.

其實也不一定要走https 就能達成目地, 只要在 docker client 修改 daemon.json,加上

"insecure-registries" : ["docker.local"] 

然後讓內部用的repository 使用 80port的http 就可以了 。
但缺點就是,每個docker client都要去修改 daemon.json。

所以為了避免去注意到底daemon.json到了改了沒(說到底還是懶) ,使用https還是比較好的做法。

環境

https://www.sonatype.com/download-oss-sonatype 下載最新版本 Nexus Repository OSS , 目前我是使用 3.16 的版本

步驟

以下步驟主要是參考 Nexus官方文件 https://help.sonatype.com/repomanager3/security/configuring-ssl#ConfiguringSSL-InboundSSL-ConfiguringtoServeContentviaHTTPS

1.用 OpenSSL tool產生給要private repository使用的domain (以 docker.local 為例)憑証 ,產生出來的格式要pfx , 而且匯出時一定要有6個字以上的密碼 ,這裡假設 檔名叫docker.local.pfx, 密碼是123456

怎麼用OpenSSL產生憑証可以參考黑暗大的這篇 https://blog.darkthread.net/blog/iis-ssl-cert-by-openssl/

還有記得要把簽發SSL憑証的根憑証匯到 docker client [本機電腦]層級的[受信任的根憑証單位]裡 , 如果有AD的環境可以用群組原則物件(GPO)派發到每一台電腦參考
https://docs.microsoft.com/zh-tw/windows-server/identity/ad-fs/deployment/distribute-certificates-to-client-computers-by-using-group-policy

2.用 java sdk 附的keytool 將步驟 1 產出的憑証轉成 jks 格式,檔名叫keystore.jks

範例

 "C:\Program Files\Java\jdk1.8.0_161\bin\keytool" -importkeystore -srckeystore docker.local.pfx -srcstoretype PKCS12 -srcstorepass 123456 -destkeystore keystore.jks -deststoretype jks -deststorepass 123456

3.把keystore.jks放到 Nexus 的安裝目錄下的/etc/ssl/ 裡

4.修改安裝目錄下的/etc/nexus-default.properties

#讓管理介面可以使用https port用 8443
application-port-ssl=8443

#把nexus-args= 那一行 變成 
nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-https.xml,${jetty.etc}/jetty-requestlog.xml

5.修改安裝目錄下的/etc/jetty/jetty-https.xml

把下列這3個值都改成憑証的密碼,這邊範例是123456

<Set name="KeyStorePassword">123456</Set>  
<Set name="KeyManagerPassword">123456</Set>  
<Set name="TrustStorePassword">123456</Set>  

6.重啟nexus這個windows 服務(如果有把nexus變成windows 服務)

7.用https://docker.local:8443 如果有連上管理介面就表示有啟用成功

8.然後就可以到管理介面把內部用的repository , 使用https打勾 ,內容填上443

9.用browser連 https://docker.local 有回應就表示設定成功

10.到docker client 使用login的指令測試是否有成功

docker login docker.local

如果出現詢問帳密 就表示設定成功

如果出現

Get https://docker.local/v2/: x509: certificate signed by unknown authority 

表示沒有把docker.local.pfx 的根憑証, 匯入到[本機電腦]層級的[受信任的根憑証單位]裡