1、使用Docker测试静态网站
Eg:将Nginx安装到容器来架构一个简单的网站Sample:
(1)先创建一个目录来保存Dockerfile:
~$ mkdir sample //创建目录,存放Dockerfile文件
~$ cd sample
~$ touch Dockerfile //touch:修改指定文件的时间标签,把已存在的文件的时间标签更新为系统当前时间(默认方式),
//它们的数据原封不动的保存下来;若该文件尚未存在,则创建一个空新文件;
(2)配置Nginx:下载配置文件;
~$ cd sample
~$ mkdir nginx && cd nginx //创建nginx目录,存放nginx配置文件,并进入目录
~$ wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/nginx/global.conf //获取nginx配置文件
~$ wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/nginx/nginx.conf
// 配置文件`global.conf`:
server {
listen 0.0.0.0:80; //将Nginx设置为监听80端口
server_name _;
root /var/www/html/website; //设置网络服务的根路径(RUN指令创建的)
index index.html index.htm;
access_log /var/log/nginx/default_access.log;
error_log /var/log/nginx/default_error.log;
}
// 配置文件nginx.conf
user www-data;
worker_processes 4;
pid /run/nginx.pid;
daemon off; //阻止Nginx进入后台,强制其在前台运行;
//这是因为要想保持Docker容器活跃状态,需要其中运行的进程不能中断;
//默认情况下,Nginx会以守护进程的方式启动,这会导致容器只是短暂运行;
//将Nginx配置为非守护进程的模式,so可以让Nginx在Docker容器中工作;
events { }
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_disable "msie6";
include /etc/nginx/conf.d/*.conf;
}
(3)编写Dockerfile文件:
~$ cd sample && vi Dockerfile //使用vi编辑器编写Dockerfile内容,然后保存退出
FROM ubuntu:14.04 //基础镜像为ubuntu
MAINTAINER zxj "13116088888"
ENV REFRESHED_AT 2018-06-29 //设置环境变量
RUN apt-get update //更新数据源库
RUN apt-get -y -q install nginx //安装nginx,-y:一路yes,-q:输出到日志 - 无进展指示;
RUN mkdir -p /var/www/html //-p:若路径中的父目录不存在,则创建
ADD nginx/global.conf /etc/nginx/conf.d/ //复制文件到指定路径,并自动解压
ADD nginx/nginx.conf /etc/nginx/nginx.conf //将已下载的本地文件的Nginx的配置文件添加到镜像中;
EXPOSE 80 //公开镜像的80端口
Nginx配置文件是为了运行sample网站而配置的;将文件nginx/global.conf
用ADD指令复制到/etc/nginx/conf.d/
目录下,将文件/etc/nginx.conf
复制到/etc/nginx
目录下;
(4)利用Dockerfile文件构建Sample网站和Nginx镜像
~$ docker build -t zxj/nginx . //在当前目录(.)下构建镜像并命名为zxj/nginx
(5)创建一个被测的Sample网站:
~$ cd sample
~$ mkdir website && cd website //在构建环境下创建目录website,用于存放sample网站的东西
~$ wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/website/index.html //下载Sample网站的index.html文件到website目录中
(6)根据镜像创建Nginx测试容器:
~$ cd sample //进入到构建环境目录下,下面一条指令$PWD获取到目录应该是/home/zxj/sample路径
~$ docker run -d -p 80 --name website -v $PWD/website:/var/www/html/website zxj/nginx nginx // `$PWD` 获得当前工作目录路径的字符串值;
-
执行
docker run
命令时传入了nginx作为容器的启动命令;一般情况下,这个命令无法让Nginx以交互式的方式运行,但是我们已经在提供给Docker的配置(nginx.conf
)里面加入了指令daemon off,这个指令让Nginx启动后以交互式的方式在前台运行; -
-v
:将宿主机的目录作为卷,挂在到容器里;
指定卷的源目录(本地宿主机的目录)和容器里的目的目录,两个目录通过冒号来分隔;若目的目录不存在,Docker会自动创建;可以通过在目的目录后面加上:rw / :ro
来指定目的目录的读写状态; -
在Nginx网站容器里,我们通过卷将
$PWD/website
挂载到容器的/var/www/html/website
目录,顺利挂载了正在开发的本地网站;在Nginx配置里(global.conf中),已经指定了这个目录为Nginx服务器的工作目录;
(7)使用ps 命令查看正在运行的容器:
~$ docker ps //可以看到名为website的容器正在处于活跃状态,其80端口被映射到32770端口;
(8)在Docker宿主机上浏览32770端口,可以看到Sample网站:
(9)修改网站:
网站已经运行起来了,若现在要修改网站,可以直接打开本地宿主机的website目录下的index.html文件并修改:~$ vi $PWD/website/index.html
,This is a website for Docker.
然后刷新浏览器即可;
2、使用Docker构建并测试Web应用程序
接下来要测试一个基于Sinatra的Web应用程序,而不是静态网站;演示如何在Docker里开发并测试应用程序,这个应用程序会接收输入的参数,并使用JSON散列输出这些参数;
(1)构建Sinatra应用程序 - 编写Dockerfile - 构建镜像:
~$ mkdir sinatra //创建Sinatra目录
~$ cd sinatra //进入Sinatra目录
~$ touch Dockerfile //创建Dockerfile文件
~$ vi Dockerfile //使用vi编辑器编写dockerfile文件,然后保存并退出
~$ sudo docker build -t zxj5203/sinatra . //编写完Dockerfile文件之后,构建新镜像
-------------------------------------------------------------------------
FROM ubuntu:14.04
MAINTAINER zxj "13116088888"
ENV REFRESHED_AT 2018-06-29 //设置环境变量
//安装Ruby和RubyGem,并使用gem安装sinatra、json、redis包;
RUN apt-get update
RUN apt-get -y install ruby ruby-dev build-essential redis-tools
RUN gem install --no-rdoc --no-ri sinatra json redis
RUN mkdir -p /opt/webapp //创建新目录来存放新的Web应用程序
EXPOSE 4567 //公开WEBrick的默认端口4567
CMD ["/opt/webapp/bin/webapp"] //指定[]里面内容作为Web应用程序的启动文件
- 注意:gem安装Redis的时候,可能会出错:
redis requires Ruby version >= 2.2.2.
;
- 原因:默认支持ruby到2.0.0,可gem 安装redis需要最低是2.2.2;
- 解决办法:先安装rvm,再把ruby版本提升至2.3.3:
- 参考链接:https://www.cnblogs.com/carryping/p/7447823.html
curl -sSL https://get.rvm.io | bash -s stable
- 若执行命令出错:
- 则执行下面命令:
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
source /home/zxj/.rvm/scripts/rvm
- 查看rvm库中已知的ruby版本:
rvm list known
- 选择>=2.2.2的Ruby版本进行安装:
rvm install 2.3.7
- 使用刚才下载的ruby版本:
rvm use 2.3.7
- 查看安装的Ruby版本:
ruby --version
; - 重新安装Redis:
gem install redis
,或者重新build Dockerfile:cd sinatra && docker build -t zxj/sinatra .
;
(2)创建Sinatra容器:
创建镜像之后,下载Sinatra Web程序的源代码,这个应用程序在webapp目录下,由bin和lib两个目录组成;
- GitHub仓库:https://github.com/jamtur01/dockerbook-code
- 官网:http://dockerbook.com/code/5/sinatra/webapp/ (失效)
- bin目录内容:https://github.com/turnbullpress/dockerbook-code/blob/master/code/5/sinatra/webapp/bin/webapp
- lib目录内容:< https://github.com/turnbullpress/dockerbook-code/blob/master/code/5/sinatra/webapp/lib/app.rb>
~/sinatra$ wget --cut-dirs=7 -nH -r --no-parent https://github.com/turnbullpress/dockerbook-code/tree/master/code/5/sinatra/webapp/ // 下载的内容有错误;不用这种方式下载;
-------------------------------------------------------------------------
// 手动创建目录,分别下载文件;
~/sinatra$ mkdir webapp && cd webapp
~/sinatra/webapp$ mkdir bin && cd bin
~/sinatra/webapp/bin$ wget https://raw.githubusercontent.com/turnbullpress/dockerbook-code/master/code/5/sinatra/webapp/bin/webapp
~/sinatra/webapp$ mkdir lib && cd lib
~/sinatra/webapp/lib$ wget https://raw.githubusercontent.com/turnbullpress/dockerbook-code/master/code/5/sinatra/webapp/lib/app.rb
~/sinatra$ ls -l webapp //列出webapp文件夹内容
~/sinatra$ chmod +x $PWD/webapp/bin/webapp //修改webapp文件的属性为可执行的
--cut-dirs=7
:减掉主机名后面的相对目录数,避免创建n多层目录;nH
:不创建主机名目录;r
:递归下载子目录;--no-parent
: Don´t download something from the parent directory;
(3)从镜像创建新sinatra容器:
sudo docker run -d -p 4567 --name webapp -v $PWD/webapp:/opt/webapp zxj5203/sinatra
-
创建了一个新的名为webapp的容器,制定了一个新卷$PWD/webapp,来存放sinatra应用程序;并将这个卷挂在Dockerfile里创建的目录/opt/webapp;
-
没有在命令行中提供要运行的命令,而是在Dockerfile里的CMD指令中提供了这个命令:
CMD ["/opt/webapp/bin/webapp"]
-
sudo docker logs webapp
:查看被执行的命令都输出了什么; -
sudo docker top webapp
:查看容器里正在运行的进程; -
sudo docker port webapp 4567
:查看容器的端口映射到了本地宿主机的哪个端口;
(4)使用curl命令测试应用程序:
curl -i -H 'Accept:application/json' -d 'name=Foo&status=Bar' http://localhost:32779/json
:给sinatra应用程序传入一些参数,这些参数转化成JSON散列后输出;
(5)构建Redis镜像和容器:
扩展sinatra应用程序,加入Redis后端数据库,并在数据库中存储输入的参数;
需要构建新的镜像和容器来运行Redis数据库,然后利用Docker的特性来关联两个容器;
- Dockerfile:
FROM ubuntu:18.04
MAINTAINER zxj "13116088888"
ENV REFRESHED_AT 2019-06-10
RUN apt-get update
RUN apt-get -y install redis-server redis-tools
EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server"]
CMD []
sudo docker build -t zxj5203/redis .
:构建Redis镜像;sudo docker run -d -p 6379 --name redis zxj5203/redis
:启动Redis容器;sudo docker port redis 6379
:查看容器端口映射到宿主机的哪个端口;sudo apt-get -y install redis-tools
:在本地安装Redis客户端做测试,客户端程序一般在Redis-tools包里;redis-cli -h 127.0.0.1 -p 32780
:使用redis-cli命令来确认Redis服务器是否正常工作;
(6)连接Redis容器:
sudo docker inspect redis
:查看Redis容器的网络配置;
sudo docker inspect -f '{{.NetworkSettings.IPAddress}}' redis
:查看Redis容器的IP地址;
redis-cli -h 172.17.0.4
:直接与Redis容器通信;
使用这种方式连接Redis有问题:要在应用程序中对Redis容器的IP地址做硬编码,如重启Redis容器,docker会改变Redis容器的IP地址;
(7)让Docker容器互连:
-
停止并删除webapp、redis两个容器;
-
sudo docker run -d --name redis zxj5203/redis
:重新创建一个Redis容器,不用公开容器的端口; -
sudo docker run -i -t -p 4567 --name webapp --link redis:db -v $PWD/webapp:/opt/webapp zxj5203/sinatra /bin/bash
:启动web应用程序,并把它连接到Redis容器中; -
root@deec416db260:/# cat /etc/hosts
:在父容器里面查看连接信息;信息包括容器自己的IP地址和主机名、子容器的IP地址和该连接的别名衍生的主机名;
重启子容器时容器的IP地址会发生变化,若被连接的容器重启了,/etc/hosts文件中的IP地址会同时更新; -
root@deec416db260:/# env
:显示用于连接的环境变量;
Docker在连接父子容器时,会自动创建一些以子容器别名开头的环境变量;自动创建的环境变量包括:子容器的别名,容器里运行的服务所使用的协议、IP和端口号,容器里运行的不同服务所指定的协议、IP和端口号,容器里由Docker设置的环境变量的值;
(8)使用容器连接来通信: 给父容器应用程序加入一些连接信息,以便与子容器通信;
- 方法1:使用环境变量里的一些连接信息:
- 方法2:使用DNS和/etc/hosts信息:
(9)测试支持Redis的sinatrat应用程序:
3、构建自己的镜像 - myforum
~ (1)制作镜像Tomcat - 将项目war包文件 装进镜像中
1、进入到/usr/local/docker/tomcat
目录,创建Dockerfile文件;
2、将项目的打包文件上传到服务器的这个目录;(本地项目目录下的taget目录下的,与war包同名的文件夹打包zip,是进入到文件夹里面,选中所有文件,右键压缩)
3、在/usr/local/docker/tomcat
下docker build -t myforum .
4、docker run -it --rm myforum bash
FROM tomcat
WORKDIR /usr/local/tomcat/webapps/ROOT
RUN rm -rf *
COPY myforum-0.0.1-SNAPSHOT.zip .
RUN unzip myforum-0.0.1-SNAPSHOT.zip
RUN rm -f myforum-0.0.1-SNAPSHOT.zip
WORKDIR /usr/local/tomcat
EXPOST 8080
部署项目到容器时,不使用这种方法,因为这个是把项目的war包直接拷贝到了镜像中,修改项目代码时就需要重新制作镜像;一般是将ROOT目录以数据卷的形式挂载;
~ (2)拉取镜像MySQL - 配置mysql
1、拉取镜像:docker pull mysql:5.7.26
需要指定5.x.x
版本;因为默认拉取的最新版本是8.x.x
版本的;
8.x.x
比5.x.x
快2倍;
8.x.x
新特性:取消了MyISAM引擎;
5.x.x
有MyISAM和InnoDB两种引擎;InnoDB引擎支持事务,所以效率会降低,MyISAM不支持事务,查询效率高;8.x.x
取消了MyISAM引擎,所以InnoDB既支持事务,效率也提高了;
现在的企业在向互联网转型,所以需要互联网的开发技能:分布式系统开发;
分布式系统开发就需要数据库也支持分布式,现在的数据库分布式解决方案使用的是第三方方案,8.0是支持原生分布式数据库解决方案的;
2、运行镜像:(-d模式)
docker run -p 3306:3306 --name mysql \
-v /usr/local/docker/mysql/conf:/etc/mysql \
-v /usr/local/docker/mysql/logs:/var/log/mysql \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \ // 环境变量:在MySQL官方镜像中的启动文档中可以查看;
-d mysql:5.7.26
3、在MySQL的workbench测试连接;
4、以交互式的方式创建一个新容器:docker run -it --rm mysql:5.7.26 bash
查看MySQL路径:whereis mysql
mysq配置:root@4cbd6e7e4548:/etc/mysql/mysql.conf.d# cat mysqld.cnf
因为运行的这个容器没有指定数据卷,所以/etc/mysql
下有配置文件;
5、使用workbench导入数据库:会报错;
原因是MySQL在配置里面默认情况下,服务器可接受的文件比较小,root@4cbd6e7e4548:/etc/mysql/conf.d# cat mysqldump.cnf
查看:
6、设置MySQL初始时,服务器可以接收的文件的大小:将配置这部分做成数据卷,放到宿主机上,让配置可以被共享;不然的话容器一旦销毁,所有的配置就都没有了;
- 首先退出并删除刚才启动的容器,
- 然后以交互式方式重新启动一个容器:
docker run -p 3306:3306 --name mysql \
-v /usr/local/docker/mysql/logs:/var/log/mysql \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:5.7.26
-
以交互式方式进入容器:
docker exec -it mysql bash
root@8dda2ce3956b:/# cd /etc/mysql/conf.d
root@8dda2ce3956b:/etc/mysql/conf.d# cat mysqldump.cnf
:复制max_allowed_packet = 16M
root@8dda2ce3956b:/etc/mysql# cd mysql.conf.d
root@8dda2ce3956b:/etc/mysql/mysql.conf.d# echo "max_allowed_packet = 128M" >> mysqld.cnf
,追加到mysqld.cnf
;
cat mysqld.cnf
-
退出容器,并重启:
docker restart mysql
7、将容器里的文件复制到宿主机:将容器的/etc/mysql
文件夹整个复制;
在/usr/local/docker/mysql/conf
目录下操作;
root@Ubuntu:/usr/local/docker/mysql/conf# docker cp mysql:/etc/mysql .
:将mysql容器的/etc/mysql目录拷贝到宿主机的当前目录;
root@Ubuntu:/usr/local/docker/mysql/conf# cd mysql
root@Ubuntu:/usr/local/docker/mysql/conf/mysql# mv *.* ..
root@Ubuntu:/usr/local/docker/mysql/conf/mysql# cd ..
root@Ubuntu:/usr/local/docker/mysql/conf# rm -fr mysql
8、退出并删除刚才启动的容器;
9、删除data文件夹:root@Ubuntu:/usr/local/docker/mysql# rm -rf data
10、重新执行第二步,运行一个带有配置文件的容器;然后workbench测试连接,导入数据库,成功则说明数据卷里面的配置文件是生效的;
(3)项目的容器化部署
不使用(1)中制作的镜像,而是直接运行tomcat镜像,运行时ROOT目录一数据卷的形式挂载;
- pull tomcat;
/usr/local/docker/tomcat
:进入到目录中- 不用创建Dockerfile;
- 将项目war包导入到该目录;
- 然后创建ROOT目录;
- 将war包复制到ROOT目录,并解压缩,删除ROOT下的压缩包;
- 修改
WEB_INF/classes/db.properties
文件中的数据库地址; docker run -d -p 8080:8080 --name myforum -v /usr/local/docker/tomcat/ROOT/:/usr/local/tomcat/webapps/ROOT tomcat
:直接使用pull的Tomcat镜像run一个容器,以守护进程的方式,指定端口映射,挂载ROOT目录数据卷;- 浏览器访问:
192.168.141.176:8080