Docker 使用單一進(jìn)程容器

2018-07-24 15:26 更新

上面這種將所有服務(wù)放在一個(gè)容器內(nèi)的模式有個(gè)形象的非官方稱呼:Fat Container。與之相對的是將服務(wù)分拆到容器的模式。從Docker的設(shè)計(jì)可以看到,構(gòu)建鏡像的過程中可以指定唯一一個(gè)容器啟動的指令,因此Docker天然適合一個(gè)容器只運(yùn)行一種服務(wù),而這也是官方更推崇的。

分拆服務(wù)遇到的第一個(gè)問題就是,我們每一個(gè)服務(wù)的基礎(chǔ)鏡像從哪里來?這里有兩個(gè)選項(xiàng):

選項(xiàng)一、 統(tǒng)一從標(biāo)準(zhǔn)的OS鏡像擴(kuò)展,比如下面分別是Nginx和MySQL鏡像

FROM ubuntu:14.04
RUN  apt-get update -y && apt-get install -y nginx
FROM ubuntu:14.04
RUN  apt-get update -y && apt-get install -y mysql

這種方式的優(yōu)點(diǎn)在于所有服務(wù)可以有一個(gè)統(tǒng)一的基礎(chǔ)鏡像,對鏡像進(jìn)行擴(kuò)展和修改時(shí)可以使用同樣的方式,比如選擇了ubuntu,就可以使用apt-get指令安裝服務(wù)。

問題在于大量的服務(wù)需要自己維護(hù),特別是有時(shí)候需要某個(gè)服務(wù)的不同版本時(shí),往往需要直接編譯源碼,調(diào)試維護(hù)成本都很高。

選項(xiàng)二、 直接從Docker Hub繼承官方鏡像,下面同樣是Nginx和MySQL鏡像

FROM nginx:1.9.0
FROM mysql:5.6

Docker Hub可以看做是Docker的Github,Docker官方已經(jīng)準(zhǔn)備好了大量常用服務(wù)的鏡像,同時(shí)也有非常多第三方提交的鏡像。甚至可以基于Docker-Registry項(xiàng)目在短時(shí)間內(nèi)自己搭建一個(gè)私有的Docker Hub。

基于某個(gè)服務(wù)的官方鏡像去構(gòu)建鏡像,有非常豐富的選擇,并且可以以很小的代價(jià)切換服務(wù)的版本。這種方式的問題在于官方鏡像的構(gòu)建方式多種多樣,進(jìn)行擴(kuò)展時(shí)需要先了解原鏡像的Dockerfile。

出于讓服務(wù)搭建更靈活的考慮,我們選擇后者構(gòu)建鏡像。

為了分拆服務(wù),現(xiàn)在我們的目錄變?yōu)槿缦滤窘Y(jié)構(gòu):

~/Dockerfiles
├── mysql
│   └── Dockerfile
├── nginx
│   ├── Dockerfile
│   ├── nginx.conf
│   └── sites-enabled
│       ├── default.conf
│       └── evaengine.conf
├── php
│   ├── Dockerfile
│   ├── composer.phar
│   ├── php-fpm.conf
│   ├── php.ini
│   ├── redis.tgz
└── redis
    └── Dockerfile

即為每個(gè)服務(wù)創(chuàng)建單獨(dú)文件夾,并在每個(gè)服務(wù)文件夾下放一個(gè)Dockerfile。

MySQL容器

MySQL繼承自官方的MySQL5.6鏡像,Dockerfile僅有一行,無需做任何額外處理,因?yàn)槠胀ㄐ枨蠊俜蕉家呀?jīng)在鏡像中實(shí)現(xiàn)了,因此Dockerfile的內(nèi)容為:

FROM mysql:5.6

在項(xiàng)目根目錄下運(yùn)行

docker build -t eva/mysql ./mysql

會自動下載并構(gòu)建鏡像,這里我們將其命名為eva/mysql。

由于容器運(yùn)行結(jié)束時(shí)會丟棄所有數(shù)據(jù)庫數(shù)據(jù),為了不用每次都要導(dǎo)入數(shù)據(jù),我們將采用掛載的方式持久化MySQL數(shù)據(jù)庫,官方鏡像默認(rèn)將數(shù)據(jù)庫存放在/var/lib/mysql,同時(shí)要求容器運(yùn)行時(shí)必須通過環(huán)境變量設(shè)置一個(gè)管理員密碼,因此可以使用以下指令運(yùn)行容器:

docker run -p 3306:3306 -v ~/opt/data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -it eva/mysql

通過上面的指令,我們將本地的3306端口綁定到容器的3306端口,將容器內(nèi)的數(shù)據(jù)庫持久化到本地的~/opt/data/mysql,并且為MySQL設(shè)置了一個(gè)root密碼123456

Nginx容器

Nginx目錄下提前準(zhǔn)備了Nginx配置文件nginx.conf以及項(xiàng)目的配置文件default.conf等。Dockerfile內(nèi)容為:

FROM nginx:1.9

ADD  nginx.conf      /etc/nginx/nginx.conf
ADD  sites-enabled/*    /etc/nginx/conf.d/
RUN  mkdir /opt/htdocs && mkdir /opt/log && mkdir /opt/log/nginx
RUN  chown -R www-data.www-data /opt/htdocs /opt/log

VOLUME ["/opt"]

由于官方的Nginx1.9是基于Debian Jessie的,因此首先將準(zhǔn)備好的配置文件復(fù)制到指定位置,替換鏡像內(nèi)的配置,這里按照個(gè)人習(xí)慣,約定/opt/htdocs目錄為Web服務(wù)器根目錄,/opt/log/nginx目錄為Nginx的Log目錄。

同樣構(gòu)建一下鏡像

docker build -t eva/nginx ./nginx

并運(yùn)行容器

docker run -p 80:80 -v ~/opt:/opt -it eva/nginx

注意我們將本地的80端口綁定到容器的80端口,并將本地的~/opt目錄掛載到容器的/opt目錄,這樣就可以將項(xiàng)目源代碼放在~/opt目錄下并通過容器訪問了。

PHP容器

PHP容器是最復(fù)雜的一個(gè),因?yàn)樵趯?shí)際項(xiàng)目中,我們很可能需要單獨(dú)安裝一些PHP擴(kuò)展,并用到一些命令行工具,這里我們以Redis擴(kuò)展以及Composer來舉例。首先將項(xiàng)目需要的擴(kuò)展等文件提前下載到php目錄下,這樣構(gòu)建時(shí)就可以從本地復(fù)制而無需每次通過網(wǎng)絡(luò)下載,大大加快鏡像構(gòu)建的速度:

wget https://getcomposer.org/composer.phar -O php/composer.phar
wget https://pecl.php.net/get/redis-2.2.7.tgz -O php/redis.tgz

php目錄下還準(zhǔn)備好了php配置文件php.ini以及php-fpm.conf,基礎(chǔ)鏡像我們選擇的是PHP 5.6-FPM,這同樣是一個(gè)Debian Jessie鏡像。官方比較親切的在鏡像內(nèi)部準(zhǔn)備了一個(gè)docker-php-ext-install指令,可以快速安裝如GD、PDO等常用擴(kuò)展。所有支持的擴(kuò)展名稱可以通過在容器內(nèi)運(yùn)行docker-php-ext-install獲得。

來看一下Dockerfile

FROM php:5.6-fpm

ADD php.ini    /usr/local/etc/php/php.ini
ADD php-fpm.conf    /usr/local/etc/php-fpm.conf

COPY redis.tgz /home/redis.tgz
RUN docker-php-ext-install gd \
    && docker-php-ext-install pdo_mysql \
    && pecl install /home/redis.tgz && echo "extension=redis.so" > /usr/local/etc/php/conf.d/redis.ini
ADD composer.phar /usr/local/bin/composer
RUN chmod 755 /usr/local/bin/composer

WORKDIR /opt
RUN usermod -u 1000 www-data

VOLUME ["/opt"]

在構(gòu)建過程中做了這樣一些事情:

  1. 復(fù)制php和php-fpm配置文件到相應(yīng)目錄
  2. 復(fù)制redis擴(kuò)展源代碼到/home
  3. 通過docker-php-ext-install安裝GD和PDO擴(kuò)展
  4. 通過pecl安裝Redis擴(kuò)展
  5. 復(fù)制composer到鏡像作為全局指令

按照個(gè)人習(xí)慣,仍然設(shè)置/opt目錄作為工作目錄。

這里有一個(gè)細(xì)節(jié),在復(fù)制tar包文件時(shí),使用的Docker指令是COPY而不是ADD,這是由于ADD指令會自動解壓tar文件。

現(xiàn)在終于可以構(gòu)建+運(yùn)行了:

docker build -t eva/php ./php
docker run -p 9000:9000 -v ~/opt:/opt -it eva/php

在大多數(shù)情況下,Nginx和PHP所讀取的項(xiàng)目源代碼都是同一份,因此這里同樣掛載本地的~/opt目錄,并且綁定9000端口。

PHP-CLI的實(shí)現(xiàn)

php容器除了運(yùn)行php-fpm外,還應(yīng)該作為項(xiàng)目的php cli使用,這樣才能保證php版本、擴(kuò)展以及配置文件保持一致。

例如在容器內(nèi)運(yùn)行Composer,可以通過下面的指令實(shí)現(xiàn):

docker run -v $(pwd -P):/opt -it eva/php composer install --dev -vvv

這樣在任意目錄下運(yùn)行這行指令,等于動態(tài)將當(dāng)前目錄掛載到容器的默認(rèn)工作目錄并運(yùn)行,這也是PHP容器指定工作目錄為/opt的原因。

同理還可以實(shí)現(xiàn)phpunit、npm、gulp等命令行工具在容器內(nèi)運(yùn)行。

Redis容器

為了方便演示,Redis僅僅作為緩存使用,沒有持久化需求,因此Dockerfile僅有一行

FROM redis:3.0
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號