docker-compose.yml 裡的相依性與啟動順序

簡單的說,depends_on 跟 links 只保證相依的 container 有啟動,但不保證裏面的服務已經啟動完畢,可以接受服務了。

我找到的解決方法,是利用 wait-for-it 這個 bash script 來測試 container 的 port 是否開啟。docker-compose v3 好像有要試圖解決這問題,不過還沒正式釋出。也是有一些其他的解法,不過,我覺得不是很直覺,就先放著了。

參考資料:

 

docker-machine 的 port forwarding

最近在 Windows 試 docker-toolbox,想讓外部連線連到 host 時,其實是連接到 在 VM 裡服務的 docker container,所以查了看怎麼做。

結果比想像中還要簡單,就是利用 vboxmanage controlvm 去設定 port forwarding 就可以了。

/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe controlvm vm_name natpf1 "rule1,tcp,,80,,80"

那要刪除掉這條 port forwarding 的規則,用

/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe controlvm vm_name natpf1 delete rule1

即可。

那在 linux 下也可以用同樣的方式來做 port forwarding,唯一的限制是非 root 用戶,沒辦法做 port 1024 以下的 port forwarding。

說明:

  • docker-toolbox 其實是把 docker, docker-machine, docker-compose, virtualbox 等工具包裝起來的一個便捷安裝包
  • vm_name 可以用 vboxmanage list vms 取得
  • 也可以開啟 VirtualBox ,在左側選到虛擬機,再進設定去改動。

參考資料:

Compile your go program inside the Docker container

golang 有官方製作的 container:https://hub.docker.com/_/golang/

用 docker pull golang 拉下來以後,切換到 go 專案目錄下 (假定是 $HOME/project),執行:

docker run --rm -v "$PWD":/usr/src/myapp -e GOBIN=/usr/src/myapp -w /usr/src/myapp golang:1.6 bash -c make

就可以在專案目錄下的 bin 裡找到 binary 了。

用 docker container 來 build 的好處,除了可以指定版本之外,也可以 cross compile ,另外就是可以省下處理佈署 golang 開發環境的心思。

docker-hackmd relative url

hackmd 是一個很棒的協作平台,你可以用 markdown 來撰寫文件,graphviz/flowchart 等語法來畫圖…很厲害。

安裝上也蠻簡單的,已經有人做好 Dockerfile :hackmdio/docker-hackmd: docker hackmd image

可是這個 docker image 有個問題,就是沒辦法以 relative url 存在,他預設是在根目錄下運作,有個日本人弄出來了:HackMDをnginxで / 以外のlocationで起動する。 – Qiita ,我參考他的設定,做了調整,加入 nginx 設定與 upstart 設定,放在 elleryq/docker-hackmd: docker hackmd image

大致調整以下東西:

  1. nginx 設定:加入 rewrite,將路徑改寫為 /hackmd,這可以參考 nginx.conf.example
  2. common.js:因為 hackmd 用到 websocket ,common.js 的 urlpath 也要跟著調整,否則會無法運作,裏面的 urlpath 需要修改為 /hackmd。這部份我寫在 hackmd/Dockerfile 裡,在用 git clone 取得 hackmd 原始碼以後,用 sed 去做字串的替換。
  3. upstart:upstart.hackmd.conf 裡是用 docker-compose 啟動 hackmd image ,這邊我預期 docker-compose.yml 是放在 /srv/docker-hackmd ,如果你預期不放在這兒,那麼這邊也要跟著調整。

應該大概就這些,如果有沒提到的,就看原始碼吧~

讓 docker-skype 顯示中文

公司的 skype 不知道因為裝了什麼爛掉了 (似乎是 cutegram 的樣子),怎麼弄都不行,用 web skype 過一段時間會斷線,收不到訊息。後來想到,不知道有沒有人包成 docker image,一找之下,果然有:docker-skype

試用之下,的確可以順利執行,但是中文字的部份都是方塊,看起來得自己重新包了。所以就 fork 了一份,修改了 Dockerfile 與 scripts/skype-wrapper 。

Dockerfile 主要是參考下面的文章,加上安裝字型、語言的套件與設定環境變數:

skype-wrapper 則是修改腳本,因為我在 build 時,是 tag 為 elleryq/skype ,所以這邊在 docker run 的時候,也要跟著調整,否則會執行到原來的 sameersbn/skype 。

這樣就可以用一份無汙染、無添加而且有中文的 skype 了,不過這一包真的還蠻大包,吃掉 4xxMB …

GitLab 與 Docker

之前就想要裝 GitLab,無奈,裝 GitLab 的相依性實在太多,後來就不了了之。時間飛快,今年年初時,知道了 Docker 這個東西,然後最近想到應該是可以把 GitLab 裝到 Docker 裡,這樣子 GitLab 的環境乾淨,也不會動到原本伺服器上的設定。於是就上網 Google ,果然已經有人做好了 (sameersbn/docker-gitlab),那就不囉唆,立刻來試試看。

網站上的安裝步驟其實已經蠻清楚了,這裡我就紀錄我改的部份。我用 fig 來進行客製化,所以就先下載他的 fig.yml,原本的 fig.yml 裡有三個 container,一個是 gitlab,一個是 postgresql,一個是 redis。我移掉了 postgresql 跟 redis,這邊我改用 host 的 mysql 與 redis,並且設定必要的環境變數。fig 的安裝一定要用 python2 的 pip 來安裝,否則會有問題,目前還沒移植到 python3 上。

要存取 host 的 mysql 與 redis,要注意幾點:

  1. 確定 host 的 mysql 跟 redis 是可以以 port 的方式存取,另外也要允許外部 IP 的連線。mysql 是修改 my.cnf 裡的 [mysqld] section,主要是設定 port ,重新啟動之後應該就可以;至於 redis,則是改 redis.conf 裡的 bind,將其改為 bind 0.0.0.0 ,重新啟動以後就可以。
  2. host 的 IP,在 docker container 裡,照理說是用 gateway 的 IP 就可以。一般都是找到 netstat -nr | grep '^0\.0\.0\.0' | awk '{print $2}' 這指令,但這得在 docker container 裡執行,fig.yml 裡沒辦法指定這個。後來是看到說直接用 host IP 也可以,所以我就直接指定,看起來是沒問題。

等設定好之後,直接 fig up,fig 就會幫你 pull image、建立 image 然後開始執行,第一次執行需要花一點時間。這邊我碰到的怪情況:

  1. docker 有問題,執行有問題,去查看 log ,看到 operation not supported 。查了很久,查不出來什麼問題,後來重開機,居然就沒問題了。事後猜想,可能是因為在 docker run 之前有更新過 kernel,archlinux 更新 kernel 都是使用 replace 的方式,或許是因為這樣而有問題。
  2. 使用預設的帳號跟密碼無法登入,這個得使用 docker exec -it gitlab_gitlab_1 bash 進入 container 裡,執行 sudo -u git -H bash -c “bundle exec rake gitlab:setup RAILS_ENV=production” 以後,就可以解決。

docker 小記

最近試著寫 Dockerfile,遇到了一些問題,也順利解決了,所以紀錄在這裡:

  1. 使用 apt-get install 時,會因為某些套件的安裝設定而跳出對話方塊,這會導致安裝被阻塞住。這可以藉著 debconf 來避免:
    ENV DEBIAN_FRONTEND noninteractive
    ENV TERM linux
    RUN echo ‘debconf debconf/frontend select Noninteractive’ | debconf-set-selections
    其中那兩行設置環境變數似乎不起作用的樣子,主要還是第三行。
  2. 找不到 add-apt-repository 指令。這是因為基礎的 image 裡沒有的關係,得使用 apt-get install python-software-properties 來安裝,在 Trusty ,也就是 14.04 裡,得再多安裝 software-properties-common
  3. 用 14.04 時,無法安裝 ia32-libs 。到 13.10 以後,ia32-libs 被移除了,改以 multiarch-support 替代,同時,得用 dpkg 聲明要使用 i386 architecture 才能使用 :i386,例如:
    RUN dpkg –add-architecture i386
    RUN apt-get install multiarch-support gcc-multilib g++-multilib libncurses5-dev:i386
  4. webupd8 的 Java installer 實際上是個安裝的腳本,會詢問是否同意 Oracle 的 license,才開始下載並安裝。同樣,詢問時也會阻塞住,得用下列指令事先回答同意:
    RUN echo oracle-java6-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections
    RUN apt-get install -y oracle-java6-installer
  5. apt-get install 時,都加上 -y 選項以避免詢問。
  6. 不要更動 sources.list,原因是我有試著更換為台灣的替換來源,但卻會出現無法下載某些套件的情況。
  7. 如果是要搭 Android 開發環境,下面是我在 14.04 裡試出來該要裝的套件:
    RUN apt-get install -y build-essential openjdk-7-jdk multiarch-support
    RUN apt-get install -y vim ctags cscope id-utils curl gnupg flex bison gperf zip curl libc6-dev libswitch-perl libncurses5-dev:i386 x11proto-core-dev libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 libgl1-mesa-dev gcc-multilib g++-multilib mingw32 tofrodos dialog python-markdown libxml2-utils xsltproc zlib1g-dev:i386 zlib1g-dev
  8. 清理 container 與 image 的步驟是先刪除 container,再刪除 image。用 docker ps -a -q 可以看 container id,然後用 docker rm 刪除 container,最後再用 docker rmi 去刪除 image,要砍光光,可以這樣用:
    docker ps -a -q | xargs docker rm
    docker images -q | xargs docker rmi
  9. Dockerfile 最後最好是來個 apt-get clean,可以減少 image 空間。
  10. 由於 docker 特性,image 是一層一層疊上去的,只要有指令更動,就會多一層,這有點像 git/svn repository 的概念。在用 docker build 做好 image 以後,你會想只要一個 image 就好,這時候你需要的關鍵字是 flatten 。使用的指令是 export 跟 improt:
    docker export red_panda | docker import – exampleimagelocal:new

關於 Docker push/pull

  1. 首先需要有 server,在安裝上非常簡單,你可以參考這篇 How to use your own Registry,但我發現不用那麼麻煩,有 python virtualenv 在手,可以很快裝好。
    virtualenv docker-registry-env
    cd docker-registry-env
    source bin/activate
    pip install docker-registry
    cp ./lib/python2.7/site-packages/config/config_sample.yml ./lib/python2.7/site-packages/config/config.yml
    打完上面指令就裝完了。啟動的話,接著打 docker-registry 就可以。上傳以後的 image/repository 會放在 /tmp/test ,使用的資料庫是 sqlite3 ,則是放在 /tmp/docker-registry.db。如果要調整位置,可以改 ./lib/python2.7/site-packages/config/config.yml 裡的 sqlalchemy_index_database 與 dev/test/prod 區段的 storage_path 。
  2. push 的方法,就我感覺是有點隱晦。要 push ,得先為 image 加上 tag,例如:
    docker tag 06a3d360b8e2 localhost:5000/myrepo
    docker push localhost:5000/myrepo
  3. pull 的話,就這樣用:
    docker pull localhost:5000/myrepo

資料來源: