Docker 入門(二)

引言

Docker 是一個(gè)非常有趣的項(xiàng)目钦幔。它自己宣稱可以減輕部署服務(wù)器的難度,當(dāng)然我相信里面有炒作的成分乐纸。但是實(shí)際使用后衬廷,我覺得 Docker 的表現(xiàn)還是可圈可點(diǎn)的。
Docker最大的作用就是隔絕了操作系統(tǒng)環(huán)境汽绢,類似于虛擬機(jī)吗跋,但是相對(duì)于虛擬機(jī),他又擁有絕對(duì)的高效率宁昭、和通用性

  1. docker有著比虛擬機(jī)更少的抽象層
  2. docker利用的是宿主機(jī)的內(nèi)核

所以本節(jié)為了能使大家對(duì)Docker有一個(gè)直觀的認(rèn)識(shí)跌宛,這里引用一個(gè)網(wǎng)友的實(shí)際程序來(lái)給大家講解

開始之前店溢,我們先要引入一個(gè)叫做 Image 的東西蜻韭,不過(guò)這里不是圖片的意思咳胃,他代表的是鏡像
  Docker最核心的一個(gè)概念就是鏡像峡扩,他類似于虛擬機(jī)當(dāng)中的虛擬機(jī)文件,但是又完全不同鹉戚,最直觀的感覺就是運(yùn)行一個(gè)Docker Image是非常迅速的谭贪,通常只需要幾秒鐘斤蔓!你可以從Docker的鏡像庫(kù)中下載到很多很多的鏡像隆圆,上一章的“Hello-Docker”大家還記得么漱挚,那就是其中的一個(gè),還有很多渺氧,比如說(shuō)Ubuntu,RabbitMQ等等旨涝。

這里有一個(gè)鏡像庫(kù),感興趣的同學(xué)可以去看看侣背,阿里鏡像庫(kù)

阿里鏡像庫(kù)

</br>
</br>
</br>


開始

好了白华,這里先不說(shuō)那么多復(fù)雜的概念,咱們上手試試吧秃踩!
今天衬鱼,我們要在使用Jetty + Docker快速實(shí)現(xiàn)和部署一個(gè)能顯示隨機(jī)正態(tài)分布的頁(yè)面,非常簡(jiǎn)單憔杨,最終效果如下:
我們要在使用Jetty + Docker快速實(shí)現(xiàn)和部署一個(gè)能顯示隨機(jī)正態(tài)分布的頁(yè)面,非常簡(jiǎn)單蒜胖,最終效果如下:

運(yùn)行結(jié)果(圖中的鐘型曲線是使用Java的Random.nextGaussian產(chǎn)生的消别。用戶可以在頁(yè)面上輸入限制最大值、最小值台谢、數(shù)學(xué)期望值寻狂、標(biāo)準(zhǔn)差和樣本總量并由這些參數(shù)生成正態(tài)分布圖。)

核心目標(biāo):

  1. 理解Docker兩條基本命令(打包運(yùn)行)朋沮。
  2. 了解Docker基本使用方式蛇券。

開發(fā)環(huán)境

先看看開發(fā)環(huán)境是否準(zhǔn)備好了,嗯~想一下我們需要什么,我們需要一個(gè)房子和一些零部件纠亚,房子就是我們Docker環(huán)境塘慕,零部件就是JDK環(huán)境,然后為了使應(yīng)用看起來(lái)更簡(jiǎn)單蒂胞,我們引入Groovy語(yǔ)言來(lái)代替java图呢,接著就是一個(gè)好的編輯器,vim骗随、emacs蛤织,當(dāng)然哪個(gè)順手就用哪個(gè)。

Jetty服務(wù)器

我們需要寫一個(gè)Groovy腳本來(lái)跑Jetty鸿染,首先新建一個(gè)文件夾指蚜,把這個(gè)文件夾作為這個(gè)原型的根目錄。

然后在原型根目錄中新建app.groovy作為程序入口涨椒。這個(gè)腳本主要的任務(wù)就是為我們啟動(dòng)Jetty服務(wù)器姚炕,內(nèi)容如下:

@Grab('org.eclipse.jetty.aggregate:jetty-server')
@Grab('org.eclipse.jetty.aggregate:jetty-servlet')
@Grab('javax.servlet:javax.servlet-api')
import groovy.servlet.GroovyServlet
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.DefaultServlet
import org.eclipse.jetty.servlet.ServletContextHandler

def server = new Server(8080)
def context = new ServletContextHandler(server, '/', ServletContextHandler.SESSIONS)

context.with { 
    resourceBase = 'webroot' // 使用webroot文件夾作為根目錄 
    addServlet(DefaultServlet, '/') // 掛入DefaultServlet為*.groovy腳本以外的文件提供訪問 
    addServlet(GroovyServlet, '*.groovy') // Groovy腳本用的Servlet     
    welcomeFiles = ['index.groovy'] // welcome文件設(shè)置為index.groovy,此處Optional
}
server.start()

簡(jiǎn)單說(shuō)明一下這個(gè)腳本的作用丢烘。

首先我們用@Grab抓取需要的jar包柱宦,完了之后導(dǎo)入一些Servlet和Server,然后把這些Servlet掛到端口為8080的Jetty Server上播瞳,最后啟動(dòng)Jetty掸刊。

服務(wù)器有了,接下來(lái)我們需要寫正態(tài)分布的頁(yè)面了赢乓。

正態(tài)分布

在原型根目錄下新建webroot忧侧,在其中新建一個(gè)腳本,名字隨意取牌芋,在這里我們?nèi)∶衪est1.groovy蚓炬。我不準(zhǔn)備在這里貼這個(gè)腳本的全部代碼了,你可以在這個(gè)項(xiàng)目里面看到源代碼躺屁。
  更詳細(xì)的程序說(shuō)明也可以查看這個(gè)博客肯夏,注意!這里的代碼不是重點(diǎn)犀暑,我們只是引用了這位博主的代碼驯击,大家不愿意看代碼的同學(xué)可以直接下載源碼。
  這里用到了幾個(gè)名詞需要簡(jiǎn)單說(shuō)一下

  1. java.util.Random

Java的java.util.Random中自帶一個(gè)能生成數(shù)學(xué)期望(u)是0耐亏、標(biāo)準(zhǔn)差(a)是1的近似隨機(jī)標(biāo)準(zhǔn)正態(tài)分布的隨機(jī)方法徊都,叫做nextGaussian,我們用它來(lái)生成隨機(jī)數(shù)广辰。
  由標(biāo)準(zhǔn)正態(tài)分布的特性可知暇矫,99%以上的數(shù)值落在(u-2.58a, u+2.58a)區(qū)間中主之,由于標(biāo)準(zhǔn)正態(tài)分布u = 0, a = 1所以我們可以假定nextGaussian方法生成的雙精度值范圍在-2.58 ~ +2.58之間,我們要做的只是對(duì)這個(gè)結(jié)果值做一下線性平移李根,然后收集結(jié)果即可槽奕。

  1. GroovyServlet

如果你查看groovy.servlet.ServletBinding
,可以看到在GroovyServlet中朱巨,已經(jīng)默認(rèn)綁定了以下幾個(gè)變量供我們調(diào)遣
Eager variables

  • “request” : the HttpServletRequest object
  • “response” : the HttpServletRequest object
  • “context” : the ServletContext object
  • “application” : same as context
  • “session” : shorthand for request.getSession(false) - can be null!
  • “params” : map of all form parameters - can be empty
  • “headers” : map of all request header fields

Lazy variables

  • “out” : response.getWriter()
  • “sout” : response.getOutputStream()
  • “html” : new MarkupBuilder(response.getWriter())
  • “json” : new JsonBuilder()

Methods

  • “forward(String path)” : request.getRequestDispatcher(path).forward(request, response)
  • “include(String path)” : request.getRequestDispatcher(path).include(request, response)
  • “redirect(String location)” : response.sendRedirect(location)
  1. chart.js

一個(gè)開源圖表控件史翘,參考這里的中文文檔

詳細(xì)代碼如下:

def random = new Random();
def map = [:]

int MIN = params.distMin? params.distMin.toInteger():0 // 最大值
int MAX = params.distMax? params.distMax.toInteger():100 // 最小值
int mean = params.distMean? params.distMean.toInteger():50 // 數(shù)學(xué)期望值
int sd = params.distSD? params.distSD.toInteger():2 // 標(biāo)注差
int nums = params.distTimes? params.distTimes.toInteger():100
MAX = Math.max(MAX, MIN)
MIN = Math.min(MAX, MIN)

if(MAX == MIN) {
    MAX = MIN + 100
}

if(nums <=0) {
    nums = 100
}

// System.out.println "MIN:$MIN"
// System.out.println "MAX:$MAX"
// System.out.println "mean:$mean"
// System.out.println "sd:$sd"
// System.out.println "nums:$nums"

nums.times {
    def gaussian = MIN - 1
    while(gaussian < MIN || gaussian > MAX) {
        gaussian = random.nextGaussian(); // mean 0.0, standard deviation 1.0// transform
        gaussian = (int)(sd * gaussian) + mean
    }
    // System.out.println "runs[$it]=$gaussian"
    if(map[gaussian]) {
        map[gaussian] += 1
    } else {
        map[gaussian] = 1
    }
}

// System.out.println map
def keys = map.keySet().sort()
def dataLabels = (keys[0]..keys[-1]).collect { it.toString() }
def dataList = (keys[0]..keys[-1]).collect { map[it]?:0 }

//這里動(dòng)態(tài)生成html頁(yè)面
html.html {
    head {
        title 'Gaussian Distribution Test'
        script src:'//cdn.bootcss.com/Chart.js/1.0.2/Chart.min.js'
    }
    body {
        h1 '(偽)正態(tài)分布研究'
        canvas id:'myChart', width: 800, height: 500
        form (method:'POST') {
            label ('最小值MIN') { input(type:'number', name:'distMin', placeholder:'最小值', value:"$MIN", required:'required') }
            label ('最大值MAX') { input(type:'number', name:'distMax', placeholder:'最大值', value:"$MAX", required:'required') }
            label ('數(shù)學(xué)期望值') { input(type:'number', name:'distMean', placeholder:'數(shù)學(xué)期望', value:"$mean", required:'required') }
            label ('標(biāo)準(zhǔn)差') { input(type:'number', name:'distSD', placeholder:'標(biāo)準(zhǔn)差', value:"$sd", required:'required') }
            label ('樣本總量') { input(type:'number', name:'distTimes', placeholder:'樣本總量', value:"$nums", required:'required') }
            button(type:'submit', '提交')
        }
        script {
            mkp.yield 'var data ='
        json {
            labels dataLabels
            datasets ([[
                fillColor : "rgba(151,187,205,0.5)",
                strokeColor : "rgba(151,187,205,1)",
                pointColor : "rgba(151,187,205,1)",
                pointStrokeColor : "#fff",
                data : dataList
            ]])
        }
    }
    script {
        mkp.yieldUnescaped '''
        var options = {
            //String - Colour of the scale line
            scaleLineColor : "rgba(0,0,0,.5)",
            //String - Colour of the grid lines
            scaleGridLineColor : "rgba(0,0,0,.1)",
            //Boolean - Whether to show a dot for each point
            pointDot : false,
         };
         var ctx = document.getElementById("myChart").getContext("2d");
         new Chart(ctx).Line(data, options);
         '''
        }
    }
}

運(yùn)行

重頭戲現(xiàn)在才開始,首先讓我們運(yùn)行一下上面的代碼冀续,先檢查一下工程文件是否像下圖這樣:

目錄1

webroot中包含test1.groovy文件

目錄2

好啦琼讽,讓我們?cè)谥髂夸泧L試運(yùn)行如下命令:

$ groovy app.groovy

完成!瀏覽器訪問http://localhost:8080/test1.groovy

是不是看到運(yùn)行的效果了洪唐?如果不對(duì)的話再檢查檢查钻蹬,相信不會(huì)有什么問題!

部署

這里我們先回憶一下我們需要部署什么東西凭需,首先就是java環(huán)境问欠,很多人可能要問,為什么要部署java環(huán)境粒蜈,本機(jī)上的java不是已經(jīng)安裝了么顺献?其實(shí),用上面的房子理論來(lái)解釋就是枯怖,docker他默認(rèn)是一個(gè)空房子注整,并不包含任何運(yùn)行環(huán)境,為了讓我們的工具可以運(yùn)行起來(lái)度硝,我們首先是要配置好房子里的工具肿轨,也就是運(yùn)行環(huán)境,其次才是打包我們的代碼蕊程、數(shù)據(jù)庫(kù)文件等椒袍。
  接下來(lái)就是要部署Groovy的運(yùn)行環(huán)境,配置完成以后還需要將相應(yīng)的工具配置到環(huán)境變量藻茂,就和本機(jī)配置一樣驹暑。
  Jetty呢?這個(gè)不用在容器中配置捌治,因?yàn)樗峭ㄟ^(guò)Groovy動(dòng)態(tài)引入的岗钩,這也是Groovy的一個(gè)魅力所在!我們可以用過(guò)它簡(jiǎn)化很多操作肖油,并實(shí)現(xiàn)一些Java不容易實(shí)現(xiàn)的功能。這個(gè)我在后面會(huì)單獨(dú)開一個(gè)Groovy的文章詳細(xì)說(shuō)明臂港。
總結(jié)一下:

都用到了如下這些工具:

  1. JAVA
    openjdk-8FROM java:openjdk-8-jdk
  2. Groovy
    Install groovyADD http://dl.bintray.com/groovy/maven/apache-groovy-binary-${GROOVY_VERSION}.zip /tmp/ RUN unzip -d /opt/ /tmp/apache-groovy-binary-${GROOVY_VERSION}.zip \ && rm /tmp/apache-groovy-binary-${GROOVY_VERSION}.zip

Dockerfile代碼如下:

# 使用openjdk-8
FROM java:openjdk-8-jdk

# 安裝wget和unzip
RUN apt-get update && \
    apt-get -y install wget unzip && \
    apt-get clean

# 設(shè)定環(huán)境變量
ENV GROOVY_VERSION=2.4.5
ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 \
    GROOVY_HOME=/opt/groovy-${GROOVY_VERSION}

ENV PATH=$GROOVY_HOME/bin/:$JAVA_HOME/bin:$PATH

# Install groovy
ADD http://dl.bintray.com/groovy/maven/apache-groovy-binary-${GROOVY_VERSION}.zip /tmp/

RUN unzip -d /opt/ /tmp/apache-groovy-binary-${GROOVY_VERSION}.zip \
  && rm /tmp/apache-groovy-binary-${GROOVY_VERSION}.zip

# 復(fù)制代碼
ADD ./src/ /groovyApp

EXPOSE 8080

WORKDIR /groovyApp

# 運(yùn)行g(shù)roovy
ENTRYPOINT ["groovy", "app.groovy"]

OK森枪,然后在docker環(huán)境中運(yùn)行:(如果你是docker-machine的話视搏,就是mac或者windows的docker,就是在Docker Quickstart Terminal
中县袱,對(duì)就是頭上有個(gè)金魚
鯨魚的那個(gè)終端)

這里需要注意下目錄:

目錄3

src中就是剛才的項(xiàng)目文件夾浑娜,在這個(gè)目錄中我們打開Terminal,運(yùn)行

docker build -t gaussianranddemo .

需要注意新版本的Docker規(guī)定命名必須是全部 小寫 式散!
首次運(yùn)行Groovy需要下載依賴包, 可能需要點(diǎn)時(shí)間, 請(qǐng)耐心等候....
等待Docker下載并構(gòu)建成功后運(yùn)行

docker run -d -p 8080:8080 GaussianRandDemo

-d為是否后臺(tái)運(yùn)行筋遭,如果想查錯(cuò)誤,可以把-d去掉暴拄,有異忱焯希可以調(diào)試

這個(gè)時(shí)候我們?nèi)ゲ榭?a target="_blank" rel="nofollow">http://localhost:8080/test1.groovy
如果頁(yè)面正常顯示,證明部署乖篷,運(yùn)行都已經(jīng)成功了响驴!
最后再看一眼實(shí)際運(yùn)行的效果

最終效果

排查問題

  • 如果沒有成功的話,可以去查看下端口占用情況

$ netstat -ap|grep 8080

  • 容器運(yùn)行情況

$ sudo docker ps -a


容器實(shí)例運(yùn)行狀態(tài)
  • 鏡像狀態(tài)

$ sudo docker images


鏡像狀態(tài)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末撕蔼,一起剝皮案震驚了整個(gè)濱河市豁鲤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鲸沮,老刑警劉巖琳骡,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異讼溺,居然都是意外死亡楣号,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門肾胯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)竖席,“玉大人,你說(shuō)我怎么就攤上這事敬肚”霞觯” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵艳馒,是天一觀的道長(zhǎng)憎亚。 經(jīng)常有香客問我,道長(zhǎng)弄慰,這世上最難降的妖魔是什么第美? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮陆爽,結(jié)果婚禮上什往,老公的妹妹穿的比我還像新娘。我一直安慰自己慌闭,他們只是感情好别威,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布躯舔。 她就那樣靜靜地躺著,像睡著了一般省古。 火紅的嫁衣襯著肌膚如雪粥庄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天豺妓,我揣著相機(jī)與錄音惜互,去河邊找鬼。 笑死琳拭,一個(gè)胖子當(dāng)著我的面吹牛训堆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播臀栈,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蔫慧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了权薯?” 一聲冷哼從身側(cè)響起姑躲,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盟蚣,沒想到半個(gè)月后黍析,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屎开,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年阐枣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奄抽。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蔼两,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出逞度,到底是詐尸還是另有隱情额划,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布档泽,位于F島的核電站俊戳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏馆匿。R本人自食惡果不足惜抑胎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渐北。 院中可真熱鬧阿逃,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)焊虏。三九已至淡喜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诵闭,已是汗流浹背炼团。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疏尿,地道東北人瘟芝。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像褥琐,于是被迫代替她去往敵國(guó)和親锌俱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容