溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何用Docker重新定義Java虛擬化部署

發(fā)布時間:2021-11-20 17:24:00 來源:億速云 閱讀:129 作者:柒染 欄目:云計算

如何用Docker重新定義Java虛擬化部署,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

今天就和大家分享在docker里部署java應用的實戰(zhàn)案例。

>>>Dockerfiles

Dockerfile包含了一系列指令,告訴Docker如何去構建一個鏡像,它指定了鏡像的基點,以及配置鏡像的每個細節(jié)。以下是一個Dockerfile示例,是CentOS鏡像的Dockerfile。

代碼清單1. CentOS Dockerfile

```sh
FROM scratch
MAINTAINER The CentOS Project  - ami_creator
ADD centos-7-20150616_1752-docker.tar.xz /
# Volumes for systemd
# VOLUME ["/run", "/tmp"]
# Environment for systemd
# ENV container=docker
# For systemd usage this changes to /usr/sbin/init
# Keeping it as /bin/bash for compatibility with previous
CMD ["/bin/bash"]
```

大部分內(nèi)容是注釋,主要有四句命令:
1. <code>FROM scratch</code>:所有Dockerfile都要從一個基礎鏡像繼承,在這個例子中,CentOS鏡像是繼承于"scratch"鏡像,這個鏡像是所有鏡像的根。這個配置是固定的,表明了這個是Docker的根鏡像之一。
2. <code>MAINTAINER ...</code>:<code>MAINTAINER</code>指令指明了鏡像的所有者,這個例子中所有者是CentOS Project。
3. <code>ADD centos...tar.xz</code>:<code>ADD</code>指令告訴Docker把指定文件上傳到鏡像中,如果文件是壓縮過的,會把它解壓到指定路徑。這個例子中,Docker會上傳一個CentOS操作系統(tǒng)的Gzip包,并解壓到系統(tǒng)的根目錄。
4. <code>CMD ["/bin/bash"]</code>:最后,<code>CMD</code>指令告訴Docker要執(zhí)行什么命令,這個例子中,最后會進入Bourne Again Shell (bash)終端。
現(xiàn)在你知道Docker大概是長什么樣子了,接下來再看看Tomcat官方的Dockerfile,圖2說明了這個文件的架構。

如何用Docker重新定義Java虛擬化部署

這個架構未必如你想象中那么簡單,但我們接下來會慢慢學習它,其實它是非常有邏輯的。上邊已經(jīng)提過所有Dockerfile的根是<code>scratch</code>,接下來指定的是<code>debian:jessie</code>鏡像,這個官方鏡像是基于標準鏡像構建的,Docker不需要重復發(fā)明輪子,每次都創(chuàng)建一個新鏡像了,只要基于一個穩(wěn)定的鏡像來繼續(xù)構建新鏡像即可,在這個例子中,<code>debian:jessie</code>是一個官方Debian Linux鏡像,就像上邊的CentOS一樣,它只有三行指令。

代碼清單 2. debian:jessie Dockerfile

```sh
FROM scratch
ADD rootfs.tar.xz /
CMD ["/bin/bash"]
```

在上圖中我們還見到有安裝兩個額外的鏡像,CURL 和 Source Code Management,鏡像<code>buildpack-deps:jessie-curl</code>的Dockerfile如清單3所示。

代碼清單 3. buildpack-deps:jessie-curl Dockerfile

```sh
FROM debian:jessie
RUN apt-get update && apt-get install -y --no-install-recommends \
  ca-certificates \
  curl \
  wget \
 && rm -rf /var/lib/apt/lists/*
```

這個Dockerfile中使用<code>apt-get</code>去安裝<code>curl</code>和<code>wget</code>,使這個鏡像能從其他服務器下載軟件。<code>RUN</code>指令讓Docker在運行的實例中執(zhí)行具體的命令,這個例子中,它會更新所有庫(<code>apt-get update</code>),然后執(zhí)行<code>apt-get install</code>去安裝<code>curl</code>和<code>wget</code>。

<code>buildpack-deps:jessie-scp</code>的Dockerfile如清單4所示.

代碼清單 4. buildpack-deps:jessie-scp Dockerfile

```sh
FROM buildpack-deps:jessie-curl
RUN apt-get update && apt-get install -y --no-install-recommends \
  bzr \
  git \
  mercurial \
  openssh-client \
  subversion \
 && rm -rf /var/lib/apt/lists/*
```

這個[Dockerfile]會安裝源碼管理工具,例如Git,Mercurial, 和 Subversion。

Java的[Dockerfile會更加復雜些,如清單5所示。

代碼清單 5. Java Dockerfile

```sh
FROM buildpack-deps:jessie-scm
# A few problems with compiling Java from source:
#  1. Oracle.  Licensing prevents us from redistributing the official JDK.
#  2. Compiling OpenJDK also requires the JDK to be installed, and it gets
#       really hairy.

RUN apt-get update && apt-get install -y unzip && rm -rf /var/lib/apt/lists/*
RUN echo 'deb  jessie-backports main' > /etc/apt/sources.list.d/jessie-backports.list
# Default to UTF-8 file.encoding
ENV LANG C.UTF-8
ENV JAVA_VERSION 8u66
ENV JAVA_DEBIAN_VERSION 8u66-b01-1~bpo8+1
# see

# and

ENV CA_CERTIFICATES_JAVA_VERSION 20140324
RUN set -x \
 && apt-get update \
 && apt-get install -y \
  openjdk-8-jdk="$JAVA_DEBIAN_VERSION">  ca-certificates-java="$CA_CERTIFICATES_JAVA_VERSION" \
 && rm -rf /var/lib/apt/lists/*
# see CA_CERTIFICATES_JAVA_VERSION notes above
RUN /var/lib/dpkg/info/ca-certificates-java.postinst configure
# If you're reading this and have any feedback on how this image could be
#   improved, please open an issue or a pull request so we can discuss it!
```
 
簡單來說,這個Dockerfile使用了安全參數(shù)去執(zhí)行<code>apt-get install -y openjdk-8-jdk</code>去下載安裝Java,而ENV指令配置系統(tǒng)的環(huán)境變量。

最后,清單6是Tomcat的[Dockerfile。

代碼清單 6. Tomcat Dockerfile

```sh
FROM java:7-jre
ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME
# see

RUN gpg --keyserver pool.sks-keyservers.net --recv-keys \
 05AB33110949707C93A279E3D3EFE6B686867BA6 \
 07E48665A34DCAFAE522E5E6266191C37C037D42 \
 47309207D818FFD8DCD3F83F1931D684307A10A5 \
 541FBE7D8F78B25E055DDEE13C370389288584E7 \
 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 \
 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED \
 9BA44C2621385CB966EBA586F72C284D731FABEE \
 A27677289986DB50844682F8ACB77FC2E86E29AC \
 A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 \
 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 \
 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE \
 F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23
ENV TOMCAT_MAJOR 8
ENV TOMCAT_VERSION 8.0.26
ENV TOMCAT_TGZ_URL

RUN set -x \
 && curl -fSL "$TOMCAT_TGZ_URL" -o tomcat.tar.gz \
 && curl -fSL "$TOMCAT_TGZ_URL.asc" -o tomcat.tar.gz.asc \
 && gpg --verify tomcat.tar.gz.asc \
 && tar -xvf tomcat.tar.gz --strip-components=1 \
 && rm bin/*.bat \
 && rm tomcat.tar.gz*
EXPOSE 8080
CMD ["catalina.sh", "run"]
```

嚴格來說,Tomcat使用了Java 7的父級Dockerfile(默認的最新Java版本是8)。這個Dockerfile設置了<code>CATALINA_HOME</code>和<code>PATH</code>環(huán)境變量,然后用<code>mkdir</code>命令新建了<code>CATALINA_HOME</code>目錄,<code>WORKDIR</code>指令把當前工作路徑更改為<code>CATALINA_HOME</code>,然后<code>RUN</code>指令執(zhí)行了同一行中一系列的命令:

1. 下載Tomcat壓縮包。
2. 下載文件校驗碼。
3. 驗證下載的文件正確。
4. 解壓Tomcat壓縮包。
5. 刪除所有批處理文件(我們是在Linux上運行)。
6. 刪除壓縮包文件。

把這些命令寫在同一行,對應Docker來說就是一條命令,最后Docker會把執(zhí)行的結果緩存起來,Docker有個策略是檢測鏡像何時需要重建,以及驗證構建過程中的指令是否正確。當一條指令會使鏡像更改,Docker會把每個步的結果緩存起來,Docker能把最上一個正確指令產(chǎn)生的鏡像啟動起來。

<code>EXPOSE</code>指令會讓Docker啟動一個容器時暴露指定的端口,正如之前我們啟動時那樣,我們需要告訴Docker哪個物理端口會被映射到容器上(<code>-p</code>參數(shù)),<code>EXPOSE</code>的作用就是這個定義Docker容器端口。最后Dockerfile使用catalina.sh腳本啟動Tomcat。

如何用Docker重新定義Java虛擬化部署

>>>簡單回顧

用Dockerfile從頭開始構建Tomcat是一個漫長的過程,我們總結一下目前為止的步驟:

1. 安裝Debian Linux。
2. 安裝curl和wget。
3. 安裝源碼管理工具。
4. 下載并安裝Java。
5. 下載并安裝Tomcat。
6. 暴露Docker實例的8080端口。
7. 用catalina.sh啟動Tomcat。

現(xiàn)在你應該成為一個Dockerfile專家了,下一步我們將嘗試構建一個自定義Docker鏡像。

>>>部署自定義應用到Docker

因為本篇指南主要關注點是如何在Docker中部署Java應用,而不是應用本身,我會構建一個簡單的Hello World servlet。你可以從[GitHub]獲取到這個項目,源碼并無任何特別,只是一個輸出"Hello World!"的servlet。更加有趣的是相應的[Dockerfile],如清單7所示。

代碼清單 7. Hello World servlet的Dockerfile

```sh
FROM tomcat
ADD deploy /usr/local/tomcat/webapps
```
可能看起來不大一樣,但你應該能理解以上代碼的作用是:
* <code>FROM tomcat</code>指明這個Dockerfile是基于Tomcat鏡像構建。
* <code>ADD deploy </code>告訴Docker把本地文件系統(tǒng)中的"deploy"目錄,復制到Tomcat鏡像中的 /usr/local/tomcat/webapps路徑 。

在本地使用maven命令編譯這個項目:

```sh
mvn clean install
```

這樣將會生成一個war包,target/helloworld.war,把這個文件復制到項目的docker/deploy目錄(你需要先創(chuàng)建好),最后你要使用上邊的Dockerfile構建Docker鏡像,在項目的docker目錄中執(zhí)行以下命令:

```sh
docker build -t lygado/docker-tomcat .
```

這個命令讓Docker從當前目錄(用點號.表示)構建一個新的鏡像,并用"<code>-t</code>"打上標簽<code>lygado/docker-tomcat</code>,這個例子中,lygado是我的DockerHub用戶名,docker-image是鏡像名稱(你需要替換成你自己的用戶名)。查看是否構建成功你可以執(zhí)行以下命令:

```sh
$ docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
lygado/docker-tomcat            latest              ccb455fabad9        42 seconds ago      849.5 MB
```

最后,你可以用以下命令加載這個鏡像:

```sh
docker run -d -p 8080:8080 lygado/docker-tomcat
```
這個實例啟動之后 ,你可以用以下URL訪問(請把URL中的IP替換成你虛擬機的IP):

```sh
http://192.168.99.100:8080/helloworld/hello
``` 
還是那樣,你可以用容器的ID來終止這個實例。
Docker push

一旦你構建并測試過了你的Docker鏡像,你可以把這個鏡像推送到你DockerHub的賬號中:
```sh
docker push lygado/docker-tomcat
```
這樣,你的鏡像就能被全世界訪問到了,當然,為了隱私起見,你也可以推送到私有的Docker倉庫。
下面,我們將把Docker集成到應用的構建過程,目標是在構建應用完成后,會產(chǎn)出一個包含應用的Docker鏡像。

>>>把Docker集成到Maven構建過程

在前邊的部分,我們創(chuàng)建了一個自定義的Dockerfile,并把WAR包部署到它里邊。這樣意味著把WAR包從項目的target目錄,復制到<code>docker/deploy</code>目錄下,并且從命令行中運行docker。這并沒花多少功夫,但如果你需要頻繁的改動并測試代碼,你會發(fā)現(xiàn)這個過程很煩瑣。而且,如果你需要在一個CI服務器上構建應用,并產(chǎn)出一個Docker鏡像,那你需要弄明白怎樣把Docker和CI工具整合起來。

現(xiàn)在我們嘗試一種更有效的方法,使用Maven和Maven Docker插件來構建一個Docker鏡像。

我的用例有這些:
1. 能創(chuàng)建基于Tomcat的Docker鏡像,以用于部署我的應用。
2. 能在測試中自行構建。
3. 能整合到前期集成測試和后期集成測試。

docker-maven-plugin能滿足這些需求,而且易于使用和理解。

關于 Maven Docker插件

這個插件本身有良好的[文檔],這里特別說明一下兩個主要的組件:

1. 在POM.xml中配置Docker鏡像的構建和運行。
2. 描述哪些文件要包含在鏡像中。

清單8是POM.xml中插件的配置,定義了鏡像的構建和運行的配置。

代碼清單 8. POM 文件的 build 小節(jié), Docker Maven plug-in 配置

```xml
<build>
   <finalName>helloworld</finalName>
     <plugins>
       <plugin>
         <groupId>org.jolokia</groupId>
         <artifactId>docker-maven-plugin</artifactId>
         <version>0.13.4</version>
         <configuration>
            <dockerHost>tcp://192.168.99.100:2376</dockerHost>                                         <certPath>/Users/shaines/.docker/machine/machines/default</certPath>
                <useColor>true</useColor>
                   <images>
                     <image>
                       <name>lygado/tomcat-with-my-app:0.1</name>
                       <alias>tomcat</alias>
                       <build>
                          <from>tomcat</from>
                          <assembly>
                          <mode>dir</mode
                          <basedir>/usr/local/tomcat/webapps</basedir
                          <descriptor>assembly.xml</descriptor>
                                        </assembly>
                                </build>
                                <run>
                                        <ports>
                                           <port>8080:8080</port>
                                        </ports>
                                </run>
                        </image>
                   </images>
                </configuration>
            </plugin>
        </plugins>
  </build>   
```


正如你所見,這個配置相當簡單,包含了以下元素:

Plug-in定義
<code>groupId</code>, <code>artifactId</code> 和 <code>version</code> 這些信息指定要用哪個插件。

全局設置
<code>dockerHost</code>和<code>certPath</code>元素,定義了Docker主機的位置,這些配置會用于啟動容器,以及指定Docker證書。Docker證書的路徑在<code>DOCKER_CERT_PATH</code>環(huán)境變量中能看到。

鏡像設置
在<code>build</code>元素下的所有<code>image</code>元素都定義在<code>images</code>元素下,每個<code>image</code>元素都有鏡像相關的配置,與<code>build</code>和<code>run</code>的配置一樣,主要的配置是鏡像的名稱,在這個例子中,是我的DockerHub用戶名(<code>lygado</code>),鏡像的名稱(<code>tomcat-with-my-app</code>)和鏡像的版本號(0.1)。你也可以用Maven的屬性來定義這些值。

鏡像構建配置
一般構建鏡像時,我們會使用<code>docker build</code>命令,以及一個Dockerfile來定義構建過程。Maven Docker插件也允許你使用Dockerfile,但在例子中,我們使用一個運行時生成在內(nèi)存中的Dockerfile來構建。因此,我們在<code>from</code>元素中定義父級鏡像,這個例子中是tomcat,然后在<code>assembly</code>中作其他配置。

使用Maven的<code>maven-assembly-plugin</code>,可以定義一個項目的輸出內(nèi)容,指定包含依賴,模塊,文檔,或其他文件到一個獨立分發(fā)的包中。<code>docker-maven-plugin</code>繼承了這個標準,在這個例子中,我們選擇了<code>dir</code>模式,也就是說定義在<code>src/main/docker/assembly.xml</code>中的文件會被拷貝到Docker鏡像中的basedir中。其他模式還有<code>tar</code>,<code>tgz</code>和<code>zip</code>。<code>basedir</code>元素中定義了放置文件的路徑,這個例子中是Tomcat的webapps目錄。

最后,<code>descriptor</code>元素指定了<code>assembly</code>文件,這個文件位于<code>basedir</code>中定義的<code>src/main/docker</code>中。以上是一個很簡單的例子,我建議你通讀一下相關文檔,特別地,可以了解<code>entrypoint</code>和<code>cmd</code>元素,這兩個元素可以指定啟動Docker鏡像的命令,<code>env</code>元素可以指定環(huán)境變量,<code>runCmds</code>元素類似Dockerfile中的<code>RUN</code>指令,<code>workdir</code>元素可以指定工作路徑,<code>volumes</code>元素可以指定要掛載的磁盤卷。簡言之,這個插件實現(xiàn)了所有Dockerfile中所需要的語法,所以前面所用到的Dockerfile指令都可以在這個插件中使用。

鏡像運行配置
啟動Docker鏡像時會用到<code>docker run</code>命令,你可以傳一些參數(shù)給Docker。這個例子中,我們要用<code>docker run -d -p 8080:8080 lygado/tomcat-with-my-app:0.1</code>這個命令啟動鏡像,所以我們只需要指定一下端口映射。

run元素可以讓我們指定所有運行時參數(shù),所以我們指定了把Docker容器中的8080映射到Docker宿主機的8080。另外,還可以在run這節(jié)中指定要掛載的卷(使用<code>volumes</code>),或者要鏈接起來的容器(使用<code>links</code>)。<code>docker:start</code>在集成測試中很常用,在run小節(jié)中,我們可以使用wait參數(shù)來指定一個時間周期,這樣就可以等待到某個日志輸出,或者一個URL可用時,才繼續(xù)執(zhí)行下去,這樣就可以保證在集成測試開始前鏡像已經(jīng)運行起來了。

加載依賴

<code>src/main/docker/assembly.xml</code>文件定義了哪些文件需要復制到Docker鏡像中,如清單9所示:
清單 9. assembly.xml

```xml
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
  <dependencySets>
    <dependencySet>
      <includes>
        <include>com.geekcap.vmturbo:hello-world-servlet-example</include>
      </includes>
      <outputDirectory>.</outputDirectory>
      <outputFileNameMapping>helloworld.war</outputFileNameMapping>
    </dependencySet>
  </dependencySets>
</assembly>
```
在清單 9 中,我們可以看到包含<code>hello-world-servlet-example</code>在內(nèi)的一個依賴集合,以及復制的目標路徑,<code>outputDirectory</code>這個路徑是相對于前面提到的<code>basedir</code>的,也就是Tomcat的webapps目錄。

這個插件有以下幾個Maven targets:
1. docker:build:  構建鏡像
2. docker:start: 啟動鏡像
3. docker:stop: 停止鏡像
4. docker:push: 把鏡像推送到鏡像倉庫,如DockerHub
5. docker:remove: 本地刪除鏡像
6. docker:logs: 輸出容器日志

構建鏡像
你可以從[GitHub]中獲取源碼,然后用下邊的命令構建:
```sh
mvn clean install
```
用以下命令構建Docker鏡像:
```sh
mvn clean package docker:build
```
一旦鏡像構建成功,你可以在<code>docker images</code>的返回結果中看到:
```sh
$ docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
lygado/tomcat-with-my-app   0.1                 1d49e6924d19        16 minutes ago      347.7 MB   
```
可以用以下命令啟動鏡像:

```sh
mvn docker:start
```
現(xiàn)在可以在<code>docker ps</code>中看到已經(jīng)啟動了,然后可以通過以下URL訪問:
```sh
http://192.168.99.100:8080/helloworld/hello
```
最后,可以用以下命令停止容器:
```sh
mvn docker:stop
```

Docker是一種使進程虛擬化的容器技術,它提供了一系列Docker客戶端命令來調(diào)用Docker守護進程。在Linux上,Docker守護進程可以直接運行于Linux操作系統(tǒng),但是在Windows和Mac上,需要有一個Linux虛擬機來運行Docker守護進程。Docker鏡像包含了一個輕量級的操作系統(tǒng),還額外包含了應用運行的依賴庫。Docker鏡像由Dockerfile定義,可以在Dockerfile中包含一系列配置鏡像的指令。

看完上述內(nèi)容,你們掌握如何用Docker重新定義Java虛擬化部署的方法了嗎?如果還想學到更多技能或想了解更多相關內(nèi)容,歡迎關注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI