quickfix/c++是使用FIX protocol往開交易系統時目前比較多人選用的open source函式庫。開發人員如需要使用時,可以取回quickfix/c++原始程式碼,再自行編譯及安裝後,就可以進行開發。但在有了docker後,就想要能建立一個單純的docker image以便未來可以開發或執行quickfix/c++的相關服務用的image。於是就利用些時間開始來建置。
目標很簡單,只是想要有個以Ubuntu為基底的C++開發環境,其中並且要包含了quickfix/c++的相關開發工具,盤點一下,這樣的docker image至少要有:
- gcc
- gdb
- cmake
- git
- wget
- vim
- libssl
- qfickfix/c++
建立C++開發基底
首先就是要準備一個可用於開發c++程式的docker image基底,以下是所使用的dockerfile內容。主要以ubuntu:20.04為主,加入一些開發工具,並新增ubuntu這位人員及設定其bash的基本功能。
FROM ubuntu:20.04
MAINTAINER Justin your-email@mail.server
ARG mypassword=0011111
ARG UID=1000
ARG GID=1000
ARG UName=ubuntu
RUN apt update -y
RUN TZ=Asia/Taipei \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
RUN apt install sudo vim wget git -y
RUN apt install openssh-server net-tools -y
RUN apt install build-essential cmake gdb -y
RUN mkdir -p /var/run/sshd
RUN ssh-keygen -A
RUN groupadd -g $GID $UName
RUN useradd -u $GID -g $UName $UName
RUN usermod --shell /bin/bash $UName
RUN mkdir -p /home/$UName
RUN chown $UName:$UName -R /home/$UName
USER $UName
RUN cp /etc/skel/.profile /home/$UName/.profile
RUN cp /etc/skel/.bashrc /home/$UName/.bashrc
RUN echo "export PS1='\u@\h:\w\$ '" > /home/$UName/.bashrc
RUN echo "colorscheme desert" > /home/$UName/.vimrc
USER root
RUN usermod -aG sudo $UName
RUN echo "$UName:$mypassword" | chpasswd
建置quickfix/c++函式庫
有了開發環境後,接著就是要取得quickfix/c++原始碼,並建置及安裝到docker image中。以下是新增的docker file區段:
RUN apt install libssl-dev -y
WORKDIR /tmp
RUN git clone https://github.com/quickfix/quickfix.git
WORKDIR /tmp/quickfix
RUN mkdir -p build
WORKDIR /tmp/quickfix/build
RUN cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_SSL=ON ..
RUN make && make install
RUN cp /tmp/quickfix/build/examples/executor/C++/executor /usr/local/bin
RUN cp /tmp/quickfix/build/examples/ordermatch/ordermatch /usr/local/bin
RUN cp /tmp/quickfix/build/examples/tradeclient/tradeclient /usr/local/bin
RUN rm -rf /tmp/quickfix
RUN ldconfig
WORKDIR /home
因quickfix/c++會使用到openssl,所以先安裝libssl-dev套件。接著就是取回quickfix/c++原始碼,並放到/tmp目錄中進行所需的編譯。編譯後也同時進行安裝。quickfix/c++的預設安裝,只會安裝函式庫所需的.so及.h,至於一些範例程式(例如 executor / ordermatch / tradeclient),可以依你的喜好看是否要保留。我是將它一併也複製到/usr/local/bin目錄中,方便要測試時可以確認qfickfix/c++函式庫是否都正常。
最後就是在執行一下ldconfig,以便讓系統知道quickfix.so的位置。
建置docker image
準備好上述兩份素材後,就可以將它們寫在同一份docker file中,一鍵產生所以的quickfix/c++ docker image了。以下是完整的docker file:
FROM ubuntu:20.04
MAINTAINER Justin your-email@mail.server
ARG mypassword=0011111
ARG UID=1000
ARG GID=1000
ARG UName=ubuntu
RUN apt update -y
RUN TZ=Asia/Taipei \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
RUN apt install sudo vim wget git -y
RUN apt install openssh-server net-tools -y
RUN apt install build-essential cmake gdb -y
RUN apt install libssl-dev -y
WORKDIR /tmp
RUN git clone https://github.com/quickfix/quickfix.git
WORKDIR /tmp/quickfix
RUN mkdir -p build
WORKDIR /tmp/quickfix/build
RUN cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_SSL=ON ..
RUN make && make install
RUN cp /tmp/quickfix/build/examples/executor/C++/executor /usr/local/bin
RUN cp /tmp/quickfix/build/examples/ordermatch/ordermatch /usr/local/bin
RUN cp /tmp/quickfix/build/examples/tradeclient/tradeclient /usr/local/bin
RUN rm -rf /tmp/quickfix
RUN ldconfig
WORKDIR /home
RUN mkdir -p /var/run/sshd
RUN ssh-keygen -A
RUN groupadd -g $GID $UName
RUN useradd -u $GID -g $UName $UName
RUN usermod --shell /bin/bash $UName
RUN mkdir -p /home/$UName
RUN chown $UName:$UName -R /home/$UName
USER $UName
RUN cp /etc/skel/.profile /home/$UName/.profile
RUN cp /etc/skel/.bashrc /home/$UName/.bashrc
RUN echo "export PS1='\u@\h:\w\$ '" > /home/$UName/.bashrc
RUN echo "colorscheme desert" > /home/$UName/.vimrc
USER root
RUN usermod -aG sudo $UName
RUN echo "$UName:$mypassword" | chpasswd
不過用這種方式編譯加安裝所產生的docker image檔,通常都會比較大,因為其中含有編譯所需的其它套件,以及編譯過程中的暫存檔。以我這個例子來看,原本單純的開發環境只有700MB,但加入quickfix/c++的編譯及安裝後,一個image就來到了1.7GB。
其實我們所需要的docker image中只需要那些編譯後的quickfix/c++函式庫及標頭檔就夠了。所以得想個辦法來減少docker image空間。
Multi-stage build
印象中有看到其它人使用的docker file中是包含兩段,一段是編譯所需的函式庫,只一段是拿基底再將先前編譯好的資料複製到新的基底中,這樣新的基底就含有所需的函式庫,但又不會包含到編譯過程中的暫存檔。後來查了一下才知道docker稱這種叫作Multi-stage build。
因為先前已建置好一份包含quickfix/c++開發及執行的環境的image,後續可利用另一份docker file來將所需的資料取出並複製到一個全新的基底中來使用,以下是複製的docker file:
FROM proglab/quickfix:2.1 as quickfix
FROM proglab/ubuntu-dev-v2:1.0 as base
COPY --from=quickfix /usr/local/bin /usr/local/bin
COPY --from=quickfix /usr/local/include/quickfix /usr/local/include/quickfix
COPY --from=quickfix /usr/local/lib/libquickfix.so.16.0.1 /usr/local/lib
COPY --from=quickfix /usr/local/share/quickfix /usr/local/share/quickfix
WORKDIR /usr/local/lib
RUN ln -s libquickfix.so.16.0.1 libquickfix.so.16
RUN ln -s libquickfix.so.16 libquickfix.so
WORKDIR /
RUN apt-get install gdb -y
RUN apt update -y
RUN apt upgrade -y
WORKDIR /home
RUN ldconfig
RUN mkdir -p /var/run/sshd
RUN ssh-keygen -A