這是最近項目中遇到的一個問題。在已知的部署在 docker 容器雲上某個應用中,讀寫很是頻繁,對磁盤的性能要求極高,可是又不能在同一個容器內進行高強度讀寫。另外,該主機內存資源有冗餘,容許使用特權模式運行容器,不要求該部分數據持久性存儲。html
經過對問題的分析,我採起了如下解決方案:linux
經過把內存掛載成硬盤,能夠大幅度提升磁盤的性能;git
因爲不能在同一個容器內進行讀寫,可使用 NFS 來解決; docker
容許使用特權模式,能夠在容器內部掛載磁盤;vim
不要求數據持久存儲,能夠把內存看成告訴磁盤來使用;centos
在本文中已經對涉及到公司利益部份內容進行處理,例如:文中涉及到的鏡像已經移除相關應用,直接以centos7.6.1810爲基礎鏡像。bash
CentOS Linux release 7.6.1810 (Core)
內存:256GB
#!/bin/bash UserName='gysl' PassWord='drh123' # Install the Docker engine. This needs to be executed on every machine. curl http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker-ce.repo>&/dev/null if [ $? -eq 0 ] ; then yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine>&/dev/null yum list docker-ce --showduplicates|grep "^doc"|sort -r yum -y install docker-ce-18.09.3-3.el7 rm -f /etc/yum.repos.d/docker-ce.repo systemctl enable docker --now && systemctl status docker else echo "Install failed! Please try again! "; exit 110 fi # Modify related kernel parameters. cat>/etc/sysctl.d/docker.conf<<EOF net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl -p /etc/sysctl.d/docker.conf>&/dev/null # Turn off and disable the firewalld. systemctl stop firewalld systemctl disable firewalld # Disable the SELinux. sed -i.bak 's/=enforcing/=disabled/' /etc/selinux/config # Disable the swap. sed -i.bak 's/^.*swap/#&/g' /etc/fstab # Install EPEL/vim/git. yum -y install epel-release vim git yum repolist # Add a docker user. useradd $UserName echo $PassWord|passwd $UserName --stdin usermod $UserName -aG docker # Reboot the machine. reboot
執行以上腳本重啓服務器以後,以用戶名 gysl 登陸系統。服務器
Dockefile內容以下:網絡
FROM centos:7.6.1810 ENV SSD='/high-speed-storage' SIZE='10m' COPY . / RUN yum -y install nfs-utils && \ mkdir $SSD CMD [ "/bin/bash","/start.sh" ]
start.sh腳本內容以下:app
#!/bin/bash echo "$SSD *(fsid=0,rw,no_root_squash,no_subtree_check)">>/etc/exports mount -t tmpfs -o size=$SIZE tmpfs $SSD /usr/sbin/exportfs -r /usr/sbin/rpcbind /usr/sbin/rpc.nfsd /usr/sbin/rpc.mountd /usr/sbin/rpc.rquotad while true; do sleep 6000; done
新建一個目錄,將上文中的 Dokcerfile 與 start.sh 放到該目錄。
[gysl@gysl-dev ~]$ mkdir nfs [gysl@gysl-dev ~]$ cd nfs [gysl@gysl-dev nfs]$ docker build -t nfs:v1.0 .
啓動容器內的 NFS 服務,命令以下:
[gysl@gysl-dev nfs]$ docker run -itd --privileged --rm nfs:v1.0 953dd0cf03e024447ba3a7f1be6dce6217226b25c13ffa2b9967941c96b73f4e
[gysl@gysl-dev nfs]$ docker inspect 953|grep -w 'IPAddress' "IPAddress": "172.17.0.2", "IPAddress": "172.17.0.2",
修改 Dockerfile ,內容以下:
FROM centos:7.6.1810 ENV SSD='/high-speed-storage' DATA='/data' COPY . / RUN yum -y install nfs-utils && \ mkdir $DATA CMD [ "/bin/bash","/start-client.sh" ]
添加 start-client.sh 腳本,腳本內容以下:
#!/bin/bash mount -t nfs 172.17.0.2:$SSD $DATA while true; do sleep 6000; done
新建一個目錄,把修改後的 Dockerfile 和 start-client.sh 放到同一目錄,執行命令以下:
[gysl@gysl-dev ~]$ mkdir nfs-client [gysl@gysl-dev ~]$ cd nfs-client/ [gysl@gysl-dev nfs-client]$ vi Dockerfile [gysl@gysl-dev nfs-client]$ vi start-client.sh [gysl@gysl-dev nfs-client]$ docker run --privileged -itd --rm nfs-client:v1.0 7e01276f49815b76dd4dc3ae3ff9a80b8d4f32814f46c4e58f7cfab0d945cebf
進入應用容器,查看是否掛載成功:
[root@7e01276f4981 /]# df -h Filesystem Size Used Avail Use% Mounted on overlay 8.0G 2.6G 5.5G 32% / tmpfs 64M 0 64M 0% /dev tmpfs 455M 0 455M 0% /sys/fs/cgroup /dev/mapper/centos-root 8.0G 2.6G 5.5G 32% /etc/hosts shm 64M 0 64M 0% /dev/shm 172.17.0.2:/high-speed-storage 10M 0 10M 0% /data [root@7e01276f4981 /]# touch /data/test
成功!問題解決!
不符合一個容器一個進程的容器運用的主流標準;
數據不能持久化保存,重啓容器數據會被清除;
容器存在依賴性,必須先啓動提供 NFS 服務的容器;
適用範圍狹窄;
不能經過 systemd 來管理服務;
linux下的 ramdisk 是由內核提供的,mount 命令掛載便可使用。它會被視爲塊設備,使用時須要格式化該文件系統。ramdisk 一旦建立就會佔用固定大小的物理內存,tmpfs則是動態分配。
在同一臺主機的未指定網絡方案的狀況下,Docker 是經過 bridge 的方式進行橋接的。若是涉及到跨主機的互聯,那麼可能須要使用其餘方案。
nfs-ganesha 也是 NFS 在容器中的一個比較流行的解決方案。更多資料可參閱:<https://access.redhat.com/documentation/en-US/Red_Hat_Storage/2.1/html/Administration_Guide/sect-NFS_Ganesha.html>;