Ubuntu18.04與deepin+nvidia-docker的構建與踩坑+puppeteer在docker中的使用

寫在前面的廢話

        首先說什麼docker,之前我啥也不知道,大概瞭解,就是一個集成環境,然後可以帶着這個跨越各種平臺什麼的。就這幾天的使用來看,差不多是的吧,在使用上,感覺確實是一個帶系統的集成環境,基本上和主機隔離開了,在我看來,就是一個虛擬機,然後裏面可以裝各種環境,然後還可以複製帶走,他們之間的區別不太清楚,感覺虛擬機更方便纔是,docker每次修改之後,如果不發佈的話,那就沒有了喲。
        再說明一下,其實就docker的情況,我原本就很奇怪,cuda怎麼裝,最後發現,不用裝,這裏我發了一個傻,後面再提。反正就是在docker hub上,nvidia有發佈裝好cuda的鏡像,pull下來,再自己折騰環境就可以了。

 

我的具體需求

         我這裏的需求是,有一個任務,然後很多臺電腦都需要使用,但是裝環境很麻煩,主要就是,原本我都裝好所有環境了,但是現在這個任務執行很慢,通過查詢發現,有一個模型的後處理,作者有提供c++和python兩個版本,但是c++版本需要自己編譯opencv,這個就略微的有點麻煩,在裝完一臺電腦之後,拒絕再在其他電腦上折騰了,此時老闆跟我說,整個docker吧,你應該去整個docker。
        

docker安裝

        這邊電腦分了兩個平臺三個系統,一個個來,從Ubuntu開始,在開發者中Ubuntu使用率應該很高,網上資料一查一大堆,不過很多重複的,反正以下是我收集整理使用的。

sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get -y update
sudo apt-get -y install docker-ce
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install -y nvidia-docker2

        我在第一臺電腦上是一條一條輸入的,後來可行後,就直接用一個sh腳本直接一擼到底,這裏我用的阿里雲的地址,很多資料用的是官方的,由於擔心國內網絡環境,就還是用阿里雲的吧。

        稍微解釋一下,也是幾乎所有資料說的,安裝的第一件事是刪除舊版本,如果有的話

sudo apt-get remove docker docker-engine docker.io

        然後第二件事是,安裝顯卡驅動,deb安裝很方便的,而且docker其實可以很方便的跑程序,本就可以不裝環境了,那麼就直接用系統自帶的軟件更新器,找到附加驅動安裝好了。

        然後再上面那一大串,還需要注意的是,docker沒有必要裝最新的,有特殊需要的,就記得指定版本;nvidia-docker是2,不要掉了

這裏可以稍微看一下終端消息,沒有報錯消息的話,就成功了,當然也可以按照常規方案測試一下

docker run hello-world
docker run --runtime=nvidia --rm nvidia/cuda:9.0-base nvidia-smi

第一條是測試docker,第二條是測試nvidia-docker的,尤其是第二條出現了顯卡信息,就完成了。記得前面加sudo。

順便提一下,我這邊打算裝的是cuda10.1,但是顯卡驅動是410的,後來提示驅動版本低了,所以一開始就裝高一點的版本吧。

環境搭建

         nvidia-docker是一個命令,感覺和docker差不多。首先要拉取一個鏡像,在這個操作之前,建議做兩個操作

        1.首先是解決權限問題

sudo groupadd docker
sudo gpasswd -a ${USER} docker
sudo service docker restart
newgrp - docker

基本意思就是,把當前用戶加入docker組中,這樣以後使用的時候就不用加sudo了。其中最後一步我都沒有做,直接重啓了。

稍微說一下,service docker restart是重啓docker,還可以用systemctl restart docker,兩者有沒有區別不知道,當成一個小知識點吧。

        2.接下來,處理一下磁盤佔用,docker的默認位置在/var/lib/docker中,如果你的磁盤空間不夠的話,就轉移一個位置,再在原地創建一個鏈接

sudo mv /var/lib/docker /media/PATH/data/dockerVar
sudo ln -s /media/PATH/data/dockerVar/docker /var/lib/docker

上面的PATH是各自自己的路徑,就是這個原理,知道就行了。一開始就做,會比較快,等已經有一些鏡像了,再做,就比較慢了。

        3.其實還有一個,換成阿里雲的源,在/etc/docker/daemon.json裏面的{}中,增加或者修改這一項——"registry-mirrors": ["https://fird1mfg.mirror.aliyuncs.com"]——注意是json的格式,所以別忘了加一個逗號。

在這兩個都做好後,可以去DockerHub上搜索一下鏡像,只是有的時候可能由於網絡原因,會比較慢,可以用用命令docker search,不過這個搜到的,描述太長就變省略號了,由於我需要裝好opencv的,好不容易找到一個opencv3.4.2的,結果用網頁搜索了下,發現被省略的部分寫了,是基於py2.7的,浪費表情。

稍微解釋一下,鏡像一般分兩部分,一般前部分就是這個鏡像的簡單描述,然後後面是版本(tag)以冒號隔開,如nvidia/cuda:cuda9.0-base。如果你打算使用cuda的話,建議就不要下別的,就找cuda的,我不知道能不能自己裝cuda呢,不要冒險,我都還在docker裏面編譯opencv呢,起碼這個是絕對可行的,比裝cuda好一點吧。

搜索nvidia,會出現類似下面,這些是鏡像,點進去會出現其所支持的tag

nvidia搜索結果

點擊nvidia/cuda,其實裏面的內容已經寫得比較清晰了,基本都在裏面——nvidia/cuda的所有tag——就懶得寫了,我最後選的是 10.1-cudnn7-devel-ubuntu18.04

直接

docker pull nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04

然後等着就可以了。

稍微介紹一下docker(nvidia-docker)的參數

我們下載下來的是一個鏡像,我就是理解成一個類,然後我們需要以此創建一個容器(實例)

普通的創建方法是

nvidia-docker run -it IMAGES /bin/bash

這個就是會打開這個鏡像,具體解釋省了,反正就是-it不要省略,最後一個/bin/bash,可以理解成打開這個鏡像後需要做什麼操作,然後你可以可以加一個-d後臺操作,就是後臺默默運行,然後把bash換成你需要他執行的命令,不過我用來跑程序什麼的,就是需要終端的。

  • --name 給創建的容器命名,如果不自己命令,會隨機生成一個名字,因爲在生產環境中,可能有很多個容器,做不同的操作,但是又不好區分,此時可以自己命名,但是這個名字除此之外,貌似沒有別的作用了,所以我用不着。
  • -v 本地位置映射,基本格式是"localPath:DstPath",前者是主機的路徑,注意,是需要絕對路徑,且裏面不要有外部鏈接,,容器裏面,這些鏈到外部的就斷了;後面是容器路徑,建議也寫絕對路徑,如果目錄不存在,會自己創建。個人感覺這個非常有用,起碼我可以用來傳遞文件,也可以直接把代碼放進去,而且這個路徑是實時的,我可以主機修改代碼,容器運行;可以寫多個-v來映射多個路徑;此外,這個參數網上有人做了詳細的測試,驗證各種情況,有興趣可以自己看看——linux docker 目錄掛載映射
  • -p ip端口映射,這個我理解不深,原本是想用來主機ssh docker的,後來發現似乎不用,後面會有說明。

這裏主要參考了兩篇帖子

Docker 鏡像使用,這一個主要是講了docker的一些使用方法,很實用,參數介紹很比較好,然後他有似乎是一整個教程,有上一篇下一篇,估計很有用,不過我只看了這一個

Docker & Nvidia-docker 鏡像基礎操作,這個前面部分講了怎麼安裝docker,跳過之後,後面有一些用法,比如怎麼導入導出

 

後面是踩坑,初次進去,發現目錄下的中文名字文件顯示的是一串數字,大概是沒有中文支持,具體探究就免了,直接上解決辦法

nvidia-docker run -it --name test -p 1020:22 -v /LOCAL:/DST IMAGE:TAG env LANG=C.UTF-8 /bin/bash

差不多描述了下各種參數的用法了,後面加上一個環境就可以了,再進去就發現正常了。

此時使用docker ps -a可以看到所有的容器,是不是有很多呢,每次進去就會創建一個新的容器,所以之前做的修改就木有了,且感覺很浪費,刪除容器的命令是docker rm ID,可以寫多個ID,以空格隔開,但是狀態是up的容器不可以刪除,關閉就是docker stop ID。此外也可以進入已有的容器,如果是關閉狀態的容器,先要用docker start ID打開,然後

nvidia-docker exec -it ID /bin/bash

基本上和run差不多,就是換成了exec,此外,這個exec至少需要兩個參數,也就是ID和命令(如/bin/bash),不多說了。

然後在裏面可以各種裝環境,和正常電腦一樣的,除了沒有界面外,最後測試完畢後,接下來就要上傳發布了,不然就白做了

nvidia-docker commit -m="update" -a="daniel" ID IMAGE:TAG

 稍微說明下,先exit退出當前容器,記住他的ID,然後用這個命令把這個容器發佈,變成鏡像,其中-m就是寫一下更新內容啥的,-a是作者名,ID是該容器名字,後面是生成的鏡像的名字和tag,自定義的。這個發佈不是上傳到hub上哈,別想太多,可以理解爲固定住這個容器,這個操作比較需要磁盤空間,注意前面講的,替換一下默認位置會好一點喲。當然,不做這步也是可以的不過就只能自己這臺電腦使用,還需要注意不要不小心刪除了這個容器,不然就涼了。生成鏡像之後,之前的原始鏡像就沒啥用了,刪了吧,刪除鏡像命令

docker rmi ID or IMAGES:TAG

刪除鏡像,可以通過鏡像ID來刪,不過似乎有的時候會報錯啥的,就可以指定名稱和版本號來刪。

現在需要轉移鏡像了,要先導出

nvidia-docker save -o ./IMAGE.tar  IMAGE:TAG
nvidia-docker load < ./IMAGE.tar

第一條是將一個鏡像導出成一個tar包,名稱自定義,然後生成後可以將其轉移到其他電腦上,再用load導入,"<"這個別忘了。

 基本上就是這樣了

 

        但是還沒完,此時提到主機ssh到docker上面,我試了很多辦法,網上都是說端口映射,然後就很簡單的,我怎麼都搞不定,這裏我忽略了一點,docker敲ifconfig的時候,提示沒有這個命令,然後網上說先apt install openssh-server,然後我也沒看,敲了,發現沒有下載,以爲自帶了,其實自帶的是openssh-client,後來多方找原因,比如service ssh restart會提示沒有ssh,直接ssh restart會提示沒有ip或者hostname,最後發現原來是沒有apt update,做了後可以順利安裝openssh-server,service ssh restart也可以進行了,我又發現沒有ifconfig,也沒ping,發現這個需要apt安裝

apt-get install net-tools
###   ifconfig
apt-get install iputils-ping
###  ping
apt-get install iproute2
####  ip

不過我只下了前兩個,此時可以查看docker的ip,一般是172.17.0.2,然後

apt install openssh-server

安裝ssh之後,還不行,還要修改一下/etc/ssh/sshd_config這個文件,尤其是“PermitRootLogin yes”,這一項設置是否允許root用戶登錄,docker中默認就是root用戶嘛,當然是允許啦,這樣就可以了,網上還有人說要“UsePAM no”,這一項我沒管。

ssh連接docker就這麼簡單,簡直是,爲啥網上都不寫這種操作,要我找那麼複雜的端口映射,根本看不懂,而且,因爲我映射了端口後的容器,又上傳成鏡像,結果這個鏡像的所有容器都帶有這個映射,而且是我每次嘗試的端口都有,這就讓我強迫症犯了,也不知道怎麼刪除,最後查到修改docker容器端口映射的方法這個,直接清空那幾項就可以了。

但是ssh -X 依然不能得到docker裏面的圖像數據,如有相關的顯示操作,比如"opencv.imshow"之類的會報:cannot connect to X server這樣的錯誤,我先看到這個帖子在Docker中使用GUI環境,解決cannot connect to X server問題,也就是提到ssh -X,然後就有了上面一系列操作,但是ssh可以連接之後,加了-X操作,也沒有用,事情本就告一段落了,然後今天又查了下,綜合了好幾個帖子,再在/etc/ssh/sshd_config中,設置這幾項,“X11Forwarding yes”,“X11DisplayOffset 10”,“X11UseLocalhost no”和“AllowTcpForwarding yes”順便把上面的“UsePAM no”給補上。這裏需要注意的是,不要直接添加,查找一下這幾項,把原始的註釋掉再加哦。然後就OK了,能順利打開圖像相關的操作了。

最後補一個,網上都說docker中的容器的日誌佔用非常大,而且會越來越大,然後也查了個限制的辦法,Docker 清理容器 log 日誌,他寫的很清楚,怎麼找到日誌文件,然後怎麼清空,怎麼做限制。

 

Deepin:

        這個系統不能說不好用,他就是更注重的是面向普通使用用戶,但我們開發者嘛,有的操作,這個系統就不讓用,比如cuda安裝,本來發現在Ubuntu上,用deb安裝cuda非常方便傻瓜,但是deepin他不可以,要一些稍微複雜一些的方法。

        上面ubuntu的安裝docker的代碼,deepin不能完全照搬,雖然最後還是裝好了,但是覺得,巨坑,差點換系統了。

雖然deepin的坑是滿滿的,不過網上還是查的到資源的,不過感覺比較分散,有的提供的方法解決不了問題,我這邊就我的情況,整理一下。

我這邊的系統是15.11的,前文也提到裝cuda就比較坑,然後出現一個問題,也不知道是不是因爲強行裝的原因,在一些彈出式的窗口的時候,比如iptux,還有解壓的窗口的時候,整個屏幕會一直黑屏閃爍,但是轉移焦點到其他地方,就恢復正常了,在裝這次docker的時候居然一併解決了,以下慢慢道來。

首先是裝docker,基本命令與上面一致就是要注意有幾項;

第三條執行失敗,所以我就直接打開/etc/apt/source.list,寫入"deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu bionic stable"

然後在裝docker-ce的時候,報錯,錯誤內容大概是containerd.io 的什麼版本問題,然後如果再安裝這個,又提示新的東西沒有安裝,然後通過install -f也沒啥用,後來查到可以這樣,

使用apt-cache madison docker-ce來查看可以安裝的最新版本,然後找一個版本指定該版本安裝就完了

sudo apt-get install docker-ce=18.06.3~ce~3-0~ubuntu

然後接下來

curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/ubuntu16.04/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

這兩個與上面的不同,這裏用的ubuntu16.04的,爲啥不用18.04,我也不知道,查到的別人用的就是16,我也不敢試。然後就可以

sudo apt-get update
sudo apt-get install -y nvidia-docker2
sudo pkill -SIGHUP dockerd

至此,nvidia-docker算是裝好了,但是我試了下,比如用cuda9.0base試了下nvidia-smi,會報錯,此時還是有點慌的,網上查了下,先裝一些工具、庫之類的

sudo apt-get install nvidia-opencl-common libnvidia-encode1 libnvidia-fbc1 libnvidia-ifr1 libgles1-nvidia libcuda1 nvidia-smi

我做了,但是彈出一個圖形界面,說是nvidia-installer以前通過.run安裝過,有殘留之類的,問我要不要先卸載,此時如果點擊要,則該終端卡死,點否,則以後用apt的任何東西,都會彈出這個,稍微看了下提示,貌似是不能再圖形界面做這個操作,反正最後我也沒有做,看他說可以直接delete,我就

sudo apt-get --purge remove nvidia-installer*

此時會讓卸載另外一個東西,不記得了,反正就是恰好解決了前面說的閃屏的問題,可喜可賀。

至於上面提的nvidia-docker疑似不能用的問題,還是上面那個帖子,他說的修改/etc/nvidia-container-runtime/config.toml, 將ldconfig="@/sbin/ldconfig.real"註釋掉

這個就可以了,不過貌似不做也可以,還是可以導入鏡像,然後創建容器,但是好像使用會有問題,還是要做

上面提到的帖子在這,大家可以看看deepin 15.8 安裝nvidia-docker2,我只做了那兩項。

然後就比較正常的可以創建容器,在裏面玩了。

Puppeteer在Docker上踩坑

        由於鏡像是之前ubuntu上創建好了並且可以直接使用的,本以爲這邊直接用就行了,但是結果並不如此。這從頭開始說。以下沒有特別說明,都是在ubuntu的docker中,deepin中的會專門說明。

        puppeteer是啥就多說了,在docker裏面運行,最大的坑有兩個,一個是他的依賴環境不對,我這邊最開始在本地運行的時候不覺得,因爲當時的系統裝好後第一件事就是裝一個chrome瀏覽器嘛,但是在docker那麼純淨的環境裏,啥都沒,依賴自己安裝還是比較坑的,這裏查到一個命令,可以查到缺少所有的依賴庫

ldd node_modules/puppeteer/.local-chromium/linux-641577/chrome-linux/chrome | grep not

這裏要找到你自己對應的那個版本,不過自己裝還是有點麻煩的,一定要裝的話,有個竅門,基本上直接apt install就可以,但是其名字應該是,比如libgbm.so.1,那麼就應該是apt install libgbm1;

這裏參考的資料就有好幾個:

puppeteer 在 docker 中應用出現的問題,這個其實就是解決了我的依賴問題,而且雖然他有提出去Git看官方的Troubleshooting,不過我還是直接看他的提煉內容,通過

apt-get update && \
    apt-get -y install xvfb gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 \
      libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 \
      libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 \
      libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 \
      libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget && \
    rm -rf /var/lib/apt/lists/*

通過這樣解決了,但是後面是我經歷最煩的過程,也是感覺最坑的,docker默認是以root用戶進去的,然後root用戶不能直接調用chrome,然後當時我加了--no-sandbox還是不行,官方的解決方法是,新建一個用戶,但是新建一個用戶的話,我的之前的環境就不好搞了 ,比如anaconda,然後各種查,這裏查看的太多了,我自己也亂了,其實就是還缺少一個參數——“--disable-dev-shm-usage”,也就是

this.browser = await puppeteer.launch({
  executablePath: puppeteer.executablePath(),
  args: ['--no-sandbox', '--disable-dev-shm-usage'],
});

puppeteer.executablePath()這個會返回chrome的路徑,還是很讚的。然後其實這個帖子一共提出三個問題,我只看了前兩個,第三個沒看,而這第三個就是字體問題,docker中原生沒有帶中文字體,不後來仔細看了下,他的方法要下載字體包,字體包在哪下也沒說,反正我自己解決辦法是把本機的字體移到映射的目錄內,然後在docker中再移到相應的位置,完美解決。

至此在ubuntu上的puppeteer就可以運行了,當時其實主要只參考了這一個帖子,下面的都是在deepin上發現不能用的時候查到的,也提一下

截圖的誘惑:Docker部署Puppeteer項目,這個寫的很好,只是很長,要翻到很下面纔有一些踩坑,最重要的是,我是才發現的,所這一篇對我的最大貢獻就是提供了下面這個鏈接,然後這個真的寫的很好了,可惜我當初沒有看完。

爬蟲利器 Puppeteer 實戰,這個是在上一個鏈接中找到的,他對我最大的好處就是,提供了一個cnpm,然後可以順利下載puppeteer,其實我發現node_modules這個是可以移動的,打包之後移到其他電腦,就可以直接使用,就不用重複下載了,那我爲什麼還要下載,就是他在deepin的這個docker中不知道爲啥不能用,會一直等着,直到timeout,後來看他的報錯,似乎是說必須要是對應的版本的chrome,算了算了,重新下一個好了吧,結果好像好了,這裏還有其他坑,下面再講。

Puppeteer 截圖及相關問題,這個他也是很長,前面都是實例,然後他提到了字體缺失的問題,但是他的解決方法我後來試了,沒有用,還是從有用的電腦拷貝出來最靠譜。

上面提到,在deepin的docker中,遇到在ubuntu上沒有碰到的,簡直是費解到想幹脆放棄這個系統吧,本來也是嚐鮮的,後來在多次試的時候發現,deepin的docker中不能上網,ping在之前說過已經裝好了的,而且這次也不是提示沒有這個命令,是提示別的,然後多方嘗試後,發現docker容器啓動時會報 socket permission denied或者listen tcp port failed 等錯誤的原因這個帖子,雖然我和他的報錯不一樣,但是我還是把這個apparmor給卸載了,不過他提到的什麼yml,不太懂,也不知道在哪裏,怎麼改,先算了,反正刪了後,網絡正常了,我就趕緊重新下載了puppeteer,一試,居然缺個庫,就是缺libgbm.so.1,裝好後就正常了,此時換回之前的node_modules也是正常的,所以其實就是網絡問題吧,大概,被這個apparmor害慘了。

至此,deepin中的docker已經puppeteer也能正常使用了,感覺deepin比ubuntu還要麻煩些,開發不太建議就是了。

 

WIN10的docker也是要裝的,不過還開始,以後再補吧!

20200516:今天發現,原來win10不可以安裝nvidia-docker,那就沒啥意義了,我還是可以直接裝cuda來跑深度學習的。不過那我的問題就變成了,要怎麼在不安裝vs的情況下,編譯opencv和使用c++加速,,,後來覺得,還是不要折騰了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章