顯示具有 docker 標籤的文章。 顯示所有文章
顯示具有 docker 標籤的文章。 顯示所有文章

2024-12-28

在用 Docker 架設 MSSQL 時,容器的啟用會警告 [Error response from daemon: Ports are not available...]

在網路上查到的文章大至上得到的說明是,這是因為 windows 可能在某個版本的升級開始會把某些 port 或某個範圍的 port 給「保留」,其中就有包含 mssql 一般慣用的 1433/tcp,而 windows 的一個 HNS 的服務有把一些 port 給「保留」

但也有一說是因為 windows 本身使用了 Hyper-V 把 1433/tcp 給保留了起來

我比較認為是 hyper-v 的問的,因為我目前的 docker 並不是運行在 WSL2 的,還是在比較早期要用 hyper-v 的虛擬機上,所以我比較認為是 hyper-v 引起的

故,如果有跟我遇到一樣問是的,可以先用

netsh interface ipv4 show excludedportrange protocol=tcp

的指定來列出被「保留」下來的 tcp port (注: 上述的指令要用「管理員身份」去執行)

如果上述的指令沒有列出你用到的 port ,那你的問題就比較偏向是你要用的 port 已被你電腦中其他的程序佔用,又或者是其他的程序先加到他自己的「保留」了,那有以下方式你可以試試

  • netstat -ano|findstr "port"
    • 此是先找目前電腦 listen 的 port 是不是有你要用的,如果有出現,此指令也會列出用這個 port 的 process id(PID),你如果確定這個程序你沒有要用或可以改 port 那你就中止這個程序或去改 port
    • 如果沒列出來,那再走以下的建議方式
  • net stop winnat && net start winnat
    • 把 winnat 這服務重啟,這個服務重啟後再去看上述「excludedportrange」的指令,理論上應該就會列出來的項目變少了
    • 此方式理論上應該是可以直接解決問題,但只是麻煩點,有可能要你在啟動 docker 容器時發現「Ports are not available...」時就要把 winnat 服務重啟,但我覺得此方式相對保險
  • 因為認為是 hyper-v 搞的,那來對 hyper-v 處理
    1. dism.exe /Online /Disable-Feature:Microsoft-Hyper-V
      • 先把 hyper-v 這功能停用(注意: 如果你跟我一樣 docker 目前是跑在 hyper-v 上面的,這指令下去你 docker 就會異常,直到重新把 hyper-v 啟用)
    2. netsh interface ipv4 add excludedportrange protocol=tcp startport={port} numberofports=1
      • 把你的 {port} 增加到你自己要保留的設定中,這設定會讓有其他程序要用 {port} 時反而系統會告知該程序這個 {port} 已被保留不能用
    3. dism.exe /Online /Enable-Feature:Microsoft-Hyper-V /ALL
      • 重新啟用 Hyper-v(注意: 如果重新啟用 hyper-v 後 docker 啟動有問題,那建議把 docker 重新安裝)
  • reg add HKLM\SYSTEM\CurrentControlSet\Services\hns\State /v EnableExcludedPortRange /d 0 /f
    • 此項…我認為是上述的方式都不行時再用,因為畢竟要動到regedit,多少有點風險
上述的方式請在做好備份後再使用,以免有一些嚴重的風險
我個人是只有把 winnat 服務重啟的動作後,重新啟動 mssql 容器就正常了

2024-03-24

[Windows] docker desktop 4.26.0 開始會遇到 container 在啟動後維持了一定時間(大概30分鐘)時,外部host就無法對該容器進行操作

先說明,這有可能只是在下自己遇到的情況…

就是,某天在下 Windows 11 當時使用的 docker desktop 是在 4.25.0 然後更新到 4.26.0 時發生了一些奇怪的問題…

先說明在未更新前的環境

os: win11

cpu: amd ryzen 2700x

ram: 2 * 16G

app: docker desktop 4.25.0

containers: ubuntu 20.04 lts(內裝了 apache, php, mysql, phpmyadmin)

因為我大部份進行開發都是在公司上班時用工作機(筆電),當時工作機的 docker desktop 是更新到 4.25.2,家裡的桌機主要是為了在家工作時可以拿來開發,所以平時 docker desktop 我是不太會去更新

然後就有天看到有提醒有新版本 4.26.0 可以更新,我也沒想太多,就進行動作,然後更新完就把 docker desktop 關掉了,也沒去留意。

直到有天是公司 pm 告知客戶有反應前次更新有一些狀況,問我能不能先在家更新,更新完再來上班,我想說也行,就在30分鐘內完成了修正然後 hotfix 到客戶端去,正準備結束時就不知道為啥就按到了系統頁面的重新整理,結果發現一直在 loading…

2024-03-23

docker-compose 在 windows 環境該如何在 volumns 中設定掛載外部路徑

在 docker run 建立 container 的指令中,可以用 "-v {host-path}:{container-host-path}" 的方式來掛載主機路徑(host-path)至容器路徑(container-host-path)。

而主機路徑可以直接用絕對路徑的寫法,像 "-v D:\abc:/var/www/html"...

但,這方式在 docker-compose.yml 的 volumns 中這樣寫雖然不會報錯,但容器路徑 /var/www/html 卻會是空的,我假設 docker-compose.yml 中是這樣寫的(容器路徑我是假設的)
volumns:
  - "D:\abc:/var/www/html"
  - "./def:/var/www/html2"

"./def" 是以 docker-compose.yml 這個檔案的路徑開始中的 def 資料匣

我假定在 D:\abc 和 def 中都放了一個 index.html,在 container 啟動後,實際到 /var/www/html 路徑下查看,會發現是空的…而到 /var/www/html2 中查看則會有看到 index.html

在下試過很多寫法,但好像都無法掛載不是跟 docker-compose.yml 同路徑的其他路徑…但後來在 google 搜尋之後,發現了狀況,要掛載非 docker-compose.yml 同路徑的其他路徑,除了要寫絕對路徑的寫法外,寫法要改成

//{Disk drive}/path

例如: D:\abc 的掛載就要寫成

- "//d/abc:/var/www/html"

如此就能正常掛載到想要的外部路徑

註: 我自己後來把 docker desktop 在「用/不用 WSL」切換來切換去,有發現似乎「//d/abc」的這個方式是在「用 WSL」的情境下才有支援,「不用 WSL」的情境下還是要使用「D:\abc」的寫法,供大家參考

MySQL: ERROR...Aborted connection...to db: unconnected user:... host:... (init_connect command failed)... MySQL server has gone away!!

呃,沒錯,mysql 又遇坑了

不過遇上的前因是…我在把 apache, mysql, php-fpm, phpmyadmin 利用 docker 來運行在各自專屬的 container 上時,在 phpmyadmin 登入後所出現的訊息

因為這作法我沒有特別在 mysql 的 container 中去指定我自己優化的 mysql.cnf,而是改用 command 的命令加載去啟動的,所以我在 docker-compose.yml 中,mysql 的 command 的部份我有用到

command: [

...,

'--init_connect="SET NAMES utf8mb4"',

'--init_connect="SET collation_connection = utf8mb4_unicode_ci"'

]

然後 docker-compose up 的過程是沒什麼問題,當用 phpmyadmin 登入時就會看到頁面直接出現跟本篇標題差不多的文字,然後資料庫選單沒出現,重整網頁後也只是跳回登入,再次登比也是一樣。

這時我就直接進入 mysql container 內,直接用指令的方式登入

mysql -u {username} -p

剛登入是沒什麼異狀,但要求展示資料庫列表( show databases; )時就出現跟 phpmyadmin 登入時看到的異常訊息是一樣的( 註: 如果直接以高權限的帳戶登入,像 root 反而一切都很正常,沒有異常訊息 )

因為訊息中有提到 "init_connect command failed",所以先把 init_connect 的資料列出來看看

SHOW VARIABLES LIKE '%init_connect';

其結果為

| Variable_name |         Value       |
|-------------------------------------|
| init_connect  | 'SET NAMES utf8mb4' |

因為我有其他的 mysql 也有用到同樣的 init_connect 的命令,但是該命令是寫在 mysql.cnf 中,不是跟本次發生狀況的 mysql 一樣是用 docker 帶參數命令去生成的,所以我進到正常的 mysql 中看了一下,發現列出來的 init_connect 的值是不該帶有單引號的。

所以,我將 docker-compose.yml 中的 mysql 的 command 中有關於 init_connect 的命令改寫成

command: [

...,

'--init_connect=SET NAMES utf8mb4;SET collation_connection = utf8mb4_unicode_ci'

]
這樣 phpmyadmin 或 mysql 的登入就沒有再出現那個異常訊息了

2020-07-28

[2020/09/19 update] Docker for Windows 10 更新或安裝失敗的解決辦法

今天在我的 Windows 10 上的 Docker 看到要更新到 2.3.0.46911  時就出現更新失敗的訊息…我就想說直接到官網下載完整的 Docker Desktop Installer 來安裝時發現也是有錯誤。

然後就想說幹脆把目前電腦中的 docker 給移除後再重新安裝好了,但發現 docker 移除時會停滯在「Removing image & container」…上網找了一下發現好像 docker for windows 的移除常會有這個狀況。

後來在「m@rcus學習筆記」找到「[Docker] Windows 10 中移除 Docker for Windows 的另一種方式」中使用 powershell 的移除方式,雖然我執行的過程是很正常,但我還是無法繼續安裝新版本的 docker ,網頁中有說到要再執行一次 docker 捷徑讓 windows 找不到執行檔而刪除捷徑後 docker 就可以再安裝了,我試過也是不行。

後來在該篇中提到的把組態檔中的 docker 給刪除後,安裝檔就正常安裝了。

在此註記一下。

2020/09/19 更新:
後來在 2.3.0.4 要升 2.3.0.5 時又遇到一樣的狀況,本來想照原來的方式走,但後來在 docker for-win 的 github issue 中有找到比較詳細的 powershell 的移除方式「https://github.com/docker/for-win/issues/515#issuecomment-281819259」,執行完後,再去新增移除程式移除 docker 就不會再卡在「removing vm and images」了,等移除完畢後,就可以直接安裝新版的 docker for-win 了。

2020-06-03

在 docker-compose.yml 中來指定 container 的時區(timezone)

最近幫朋友處理有關 docker 的一些小問題

我朋友說他去用了別人寫好的 docker-compose ,up 之後會產生 web, db 兩個 container ,但他在操作資料時發現寫入時間不對。

後來除錯時發現其實是系統時區的問題,web 的系統是 centos 7.7 ,而 db 是 debian (版本忘了),他兩個 container 都利用「ln -sf /usr/share/zoneinfo/Asia/Taipei /etc/localtime」來設定時區,結果發現只有 db 有修正,由 utc → cst ,但 web 還是依舊維持在 cest ,沒有更動過去。

他在 web 想使用「timedatectl set-timezone Asia/Taipei」時發現出現「failed to create bus connection no such file or directory」,他上網 google 後發現有人說要讓 docker 以 privileged 模式啟動 container 才能讓 container 的 root 真的有最高權限,但也有相關資料顯示 docker container 不該以 privileged 模式啟動,因為風險很大,所以朋友就來問我看有沒有什麼方式。

從 docker-compose.yml 下手,可以在 web 與 db 的「environment」的區塊下增加「- TZ=Asia/Taipei」或「TZ: Asia/Taipei」可以讓 container 啟動後設定為 Asia/Taipei 的時區,且 web 和 db 都支援這個方式。

至於為什麼會有「- TZ=Asia/Taipei」跟「TZ: Asia/Taipei」兩種寫法,似乎是跟 docker-compose 的版本有關,後者,也就是「TZ: Asia/Taipei」是比較新式的寫法,如果有發現使用了「- TZ=Asia/Taipei」後在 up 時出現錯誤,可以修改為「TZ: Asia/Taipei」的方式來重新 up 。

另外,「- TZ="Asia/Taipei"」的寫法是錯誤的,記得不要加雙引號

2020-04-23

docker 的基礎指令說明[也許會陸續更新][2020-05-07 updated]

最近初自學,先以自己思維下寫說明,可能有一些不太對,再請大家指教…
不過主要的還是可以去看 docker commandline reference
----
pull - 由 docker hub 拉下 images 儲存
command: docker pull [appname]:[version]
appname - 如 nginx, httpd, mysql 等,有一些 app 的名字是慣用,但詳細可以上 docker hub 查
version - 指定 app 的版本,一般是看自己習慣,如果不特別指定,預設就是最新[latest]
push - 由本地的 images 推上 docker hub 發布(需有 docker hub account)
build - 以指定的 Dockerfile 重製為 image
command: docker build [OPTIONS] [New image name] [path | url]
[OPTIONS] - 很多,可參考 docker CLI reference,比較常用的如以下
--tag, -t : image tag name
--no-cache : 建置image時不使用快取
--file, -f : 指定以特定路徑下的 Dockerfile 來建置
[New image name] - 不一定要有,就是把新的 image 另名一個 REPO name
[path | url] - Dockerfile 的位置
load - 將 save 過後的 tar 重新載入為 images
command1: docker load < [package file name]
command2: docker load --input [package file name]
[OPTIONS]
--input, -i : 指定檔案,就不用 STDIN 方式("<")
--quiet, -q : 輸出較精簡的訊息,但不是寧靜模式
[package file name] : save 後的打包檔案,通常會是 tar 或 tar.gz
save - 打包 tar, 方便私下交流 images 或備份, 不用特意傳上 docker hub
command: docker save [OPTIONS] [image repo name] > [package file name]
[OPTIONS] - 基本上不用寫,因為目前只有一個 output,所以不寫的話預設就是 --output
[image repo name] - 指定 image REPOSITORY name
[package file name] - 打包後的檔名,通常會用 tar 或 tar.gz
commit - 把指定的 container 存成新的 image,簡單說是客製化,可以上 docker hub pull 別人做好的 image 下來當初始器,然後將初始器運行後,再進入內部微調成自己想要的環境,之後就可以利用 commit 將修改好的容器存成自己的 image,不過建議是使用 Dockerfile 來進行重製,commit 的方式要小心使用(可參閱 https://yeasy.gitbooks.io/docker_practice/image/commit.html )
command: docker commit [OPTIONS] [container-id] [REPOSITORY[:TAG]]
[OPTIONS] - 不一定要寫,主要看有沒有想修改原 image 的以下的東西
--author, -a : 作者資料
--change, -c : 使用 Dockerfile 中的指令來建構,有 CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | ONBUILD | USER | VOLUME | WORKDIR
--message, -m : 跟 git commit -m 'message' 的作用差不多,就是說明
--pause, -p : 暫停 container 的運作
[container-id] - 指定 container id 或者 container NAMES
run - 將指定的 images 以容器(container)方式運行起來,此容器是獨立的環境,運行的地方可以是本地的真實主機或遠端的,此容器運行時有獨立且屬於自己的作業系統、網路和處理程序
command: docker run [OPTIONS] [image[:tag]] [command] [ARGS]
[OPTIONS] - 有以下比較常用的
--detach, -d - 背景運行
--publish, -p [external-port-number[/tcp|upd]]:[internal-port-number[/tcp|udp]] - 設定容器的埠號與上層(母機?)的埠號發佈,可以特別指定對應的協定
--volumn, -v - 指定上層(母機?)的一個路徑映射並掛載於指定容器內的路徑
[image repo-name|id] - 指定要運行的鏡像名或id,這個可以在 docker pull 後使用 docker images 查詢,REPOSITORY是鏡像名,IMAGE ID 就是 id
exec - 在指定的運行中的容器內執行命令,比較常用的是開啟 terminal
command: docker exec [OPTIONS] [container id|names] [command] [ARGS]
-------
Dockerfile 一些基礎的寫法
FROM [image repo name] - 跟 docker pull 後面接的一樣
COPY [source path] [image destination path] - 把上層(或母機?)指定的檔案或路徑資料複製到新建立的image中
RUN <os shell command> - 在image建立前,運行指定的指令,在image是linux環境時,此執行環境預設是 /bin/sh,如果要使用不一樣的 shell,可使用另一種表達方式
["os shell command", "參數1", "參數2] - RUN 的另一種執行指令的模式,此模式使用 JSON 格式,[]內只能用雙引號來包住各欄位,不得使用單引號,另外要注意 “\“ 會有影響,可以改成 “\\“ 來用
ADD [外部的資料位置] [內部指令對應的資料位置] - 指定上層(母機?)的資料放入內部指定路徑中,若要放入後修改檔案擁有者屬性的話可以用另一種方式
--chown=[user|uid]:[group|gid] [外部的資料位置] [內部指令對應的資料位置] - 此方式會修改資料使用者屬性資料
ENTRYPOINT ["執行檔", "參數1", "參數2"] - json array 表達方式,在image啟動為容器時才有作用,另有 shell type 的表達方式
指令 參數1 參數2 - shell type 表達方式,在image啟動為容器時才有作用,會在 /bin/sh 的環境下執行,另有 json array 的表達方式
ENV [variable_name=path_in_image] - 設定環境變數,若有多個環境變數要設定,可以以空白隔開或用多個 ENV 來表示
[variable_name] [path_in_image] - 另一種設定表達方式,若有多個環境變數要設定,只能以多個 ENV 來表示,或改用上行表達方式
CMD ["執行檔", "參數1", "參數2"] - 啟動指定的程式,另有另一種表達方式
["參數1", "參數2"] - 此方式的參數是提供給有使用 ENTRYPOINT 的執行檔用
執行檔 參數1 參數2 - 是在 /bin/sh -c 的環境下再執行的方式
EXPOSE [port number[/tcp|udp]] - 特別指定運行後發佈的埠號,可特別指定發佈在tcp或udp上,但要記住之後以 docker run 此 image 時,在對應 --publish(-p) 時也要額外再指定協定

*注意:
- Dockerfile 的運行是逐行的,所以要留意執行順序
- ENTRYPOINT 和 CMD 之中是有關聯性的,如果有寫 ENTRYPOINT 的話就要同時寫 CMD ,如果沒有要 CMD 執行的程序,也要寫個 CMD [] 空的
- ENTRYPOINT 是用 json array 寫法還是用 shell 寫法會影響到 CMD 的執行,可以參考 Dockerfile - understand how cmd and entrypoint interact,可以參考 https://blog.tiger-workshop.com/docker-difference-between-entrypoint-and-cmd/
- 如果沒使用 ENTRYPOINT 和 CMD 的話,會繼承原來的 image 的設定
- ENTRYPOINT 和 CMD 的作用是會在啟動為容器時會發生的,只是我目前的理解的狀況,我會把 ENTRYPOINT 當作「容器啟動時會一併啟動的“程序“或“服務“」,有點像 WINDOWS 的 services.msc ,而 CMD 我會當成是「容器啟動完後自動執行的程序」(有點類似windows會放在程式集中的“啟動“)或者是「容器啟動完後受ENTRYPOINT(服務)啟動相依執行的排程」(有點類似windows在寫排程時可以設定使用者登入或網路元件已啟動時才會執行的程式)
-------
docker-compose 用法
up - 新增、重建、建立image並啟動於容器中
command: docker-compose up [OPTIONS] [docker-compose.yml path]
[OPTIONS] - 不一定要有,以下挑幾個可能比較常用的
--detach, -d : 建立好後在背景運行容器
--quiet-pull : 在建立過程時,如果有要 pull image 的訊息不顯示
--force-recreate : 強制重建,不管來源的設定或image有沒有更動過
--always-recreate-deps : 總是重建有相依性的容器,這個指令不能和 --no-recreate 一起用
--no-recreate : 如果相關的容器已存在,就不重建,這個指令不能和 --force-recreate 和 --renew-anon-volumes|-V 一起用
--no-build : 不建立 image ,就算image不存在
--no-start : 最後不啟用於容器
--build : 建立 image 優先於啟動於容器
[docker-compose.yml path] - 就是指定要運行的 docker-compose.yml 的路徑,如果沒有特別寫,會是以指令下達的當前目錄下的 docker-compose.yml
ps - 查看運行中的服務容器,跟 docker ps 類似
command: docker-compose ps