一、Docker简介
1、Docker是什么?
“Docker 是一个基于Go语言实现的开源应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。” ——百度百科
2、为什么用docker ?
1、加快应用交付速度;
传统的开发过程中,开发、测试、运维是三个独立运作的团队,团队之间沟通不畅,开发运维之间冲突时有发生,导致协作效率低下,产品交付延迟, 影响了企业的业务运行。Docker技术将应用以集装箱的方式打包交付,使应用在不同的团队中共享,通过镜像的方式应用可以部署于任何环境中。
2、系统性能的损耗也要比虚拟机低的多;
3、docker有哪些局限性?
Docker并不是全能的,设计之初也不是KVM之类虚拟化手段的替代品,简单总结几点:
1、Docker是基于Linux 64bit的,无法在32bit的linux/Windows/unix环境下使用
2、LXC是基于cgroup等linux kernel功能的,因此container的guest系统只能是linux base的
3、隔离性相比KVM之类的虚拟化方案还是有些欠缺,所有container公用一部分的运行库,(库控制受限:在沙盒里使用它是有风险的。在不知道谁以及如何创建镜像的情况下,可能会存在任意数量的有意或无意的稳定性和安全性风险。)
4、网络管理相对简单,主要是基于namespace隔离
5、cgroup的cpu和cpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是按内存收费)
6、Docker对disk的管理比较有限
7、container随着用户进程的停止而销毁,container中的log等用户数据不便收集;
8、网络限制:网络配置操作是受限的,而且到目前为止可以说这些手段都是人工的。
二、Docker安装和常用命令
1、ubuntu上安装docker:
参考:https://www.cnblogs.com/lighten/p/6034984.html
简单来说下,在ubuntu16.04上安装docker:
1) 确定kernel内核至少要在3.10版本之上:
uname -r
2) 登陆机器,用户必须使用sudo或者root权限:
sudo su
3)更新包信息,确保APT能使用https方式工作,并且CA证书已安装:
sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates
4) 添加一个新的GPG密钥:
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
5) 添加apt源:
echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list
6) 更新APT包索引:
sudo apt-get update
7)校验APT是从一个正确的仓库拉取安装包:
apt-cache policy docker-engine
8)安装linux-iamge-extra-*的kernel包,这个包允许你使用aufs存储驱动:
sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual
9)更新APT包索引:
sudo apt-get update
10)安装docker:
sudo apt-get install docker-engine
11)开启docker后台进程:
sudo service docker start
12)校验docker是否安装成功:
sudo docker run hello-world
2、docker常用命令:
1)基础命令:
docker run 启动容器
docker rm containerId 删除容器
docker ps 可以看到容器的基本信息,其中container ID很重要;(-a 查看所有存在的包括没有启动的容器)
docker exec -it [container id] bash 进入容器内部
docker images 查看镜像
2)docker大扫除:
docker kill $(docker ps -q) ;
docker rm -v $(docker ps -a -q) ;(加上-v会删除没有其它容器连接到该Volume,以及主机目录是也没被指定为Volume)
docker rmi $(docker images -q -a)
3)查看容器重启次数
docker inspect -f "{{ .RestartCount }}" container_name
查看容器最后一次的启动时间
docker inspect -f "{{ .State.StartedAt }}" container_name
查看容器cpu内存占用率
docker stats 容器名
docker-compose top
4)docker镜像离线使用:
1.将容器做成镜像:
docker commit -m "" -a "" container_id image_name (注解:-m 提示信息,-a 作者)
例:docker commit -a "jingchen" faa165fb2a5 my_mongo
2.将镜像本地化:
docker save -o local_file.tar image_name
例:docker save -o myMongodb.tar my_mongo
3.开发环境导入本地打包的镜像:
docker load -i local_file.tar
或者
docker load < local_file.tar
例:docker load -i myMongodb.tar
5)查看容器各个命令占用空间:
docker history image_name
3、docker重启策略:
- no,默认策略,在容器退出时不重启容器
- on-failure,在容器非正常退出时(退出状态非0),才会重启容器
- on-failure:3,在容器非正常退出时重启容器,最多重启3次
- always,在容器退出时总是重启容器
- unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
三、Docker实现自动化部署
1、思路和主要步骤:
1)确定需要安装的组件;
2)定制化Dockerfile,制作镜像;
3)运行docker
2、Dockerfile案列:
1)Dockerfile内容参考:
#设置继承的镜像
FROM ubuntu:16.04
# 创建者信息
MAINTAINER xianglin.zhou "xianglin.zhou@sihuatech.com"
# 设置环境变量,所有操作都是非交互式的
ENV DEBIAN_FRONTEND noninteractive
# 设置jdk的环境变量
ENV JAVA_HOME /opt/jdk
ENV PATH $JAVA_HOME/bin:$PATH
# 复制tomcat、jdk、redis和nginx.conf配置文件到镜像中
ADD jdk1.8.0_151 /opt/jdk
ADD apache-tomcat-8.5.24 /opt/tomcat-8088
RUN rm -r /opt/tomcat-8088/webapps/ROOT/*
ADD apache-tomcat-8.5.24 /opt/tomcat-8091
RUN rm -r /opt/tomcat-8091/webapps/ROOT/*
#获取宿主机的ip
ADD ip /opt/ip
#修改tomcat端口
RUN rm /opt/tomcat-8088/conf/server.xml \
&& rm /opt/tomcat-8091/conf/server.xml
ADD tomcat_conf/tomcat_8088/server.xml /opt/tomcat-8088/conf
ADD tomcat_conf/tomcat_8091/server.xml /opt/tomcat-8091/conf
ADD nginx.conf /opt
# 将war包发布到tomcat
ADD code/sihuaTech-SYS-Web.war /opt/tomcat-8088/webapps
ADD code/sihuaTech-Qlt-Web.war /opt/tomcat-8091/webapps
#将sql拷贝到容器
ADD psms2.1.sql /opt/psms2.1.sql
#前台包放在/opt下
ADD code/dist /opt/dist
# 复制启动脚本至镜像,并赋予脚本可执行权限
ADD run.sh /opt/run.sh
RUN chmod +x /opt/*.sh \
&& chmod +x /opt/tomcat-8088/bin/*.sh \
&& chmod +x /opt/tomcat-8091/bin/*.sh
#将ubuntu系统默认源改为阿里源
RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak
ADD sources.list /etc/apt
# 安装和启动redis
RUN apt-get update && apt-get -y install redis-server
#安装nginx
RUN apt-get update && apt-get -y install nginx \
&& cd /etc/nginx && rm nginx.conf && mv /opt/nginx.conf .
#安装mysql
RUN groupadd -r mysql && useradd -r -g mysql mysql
#将源改回原来的ubuntu源,不然会报错,原因未知
RUN mv /etc/apt/sources.list /etc/apt/sources.list.aliyun \
&& mv /etc/apt/sources.list.bak /etc/apt/sources.list
RUN { \
echo mysql-server mysql-server/root_password password '123456'; \
echo mysql-server mysql-server/root_password_again password '123456';\
} | debconf-set-selections \
&& apt-get update && apt-get install -y mysql-server
#配置mysql.cnf,使其可以远程登录,不区分大小写
RUN sed -i '40i lower_case_table_names=1' /etc/mysql/mysql.conf.d/mysqld.cnf \
&& sed -i 's/bind-address/#bind-address/g' /etc/mysql/mysql.conf.d/mysqld.cnf
# 暴露tomcat和redis接口
EXPOSE 8088
EXPOSE 8091
EXPOSE 6379
EXPOSE 3306
CMD ["/opt/run.sh"]
2)run.sh内容参考:
#!/bin/bash
set -x
#获取宿主机ip
ip=$(sed -r "s/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/\n\1/;s/^.*\n//" /opt/ip)
#修改nginx配置:代理ip
sed -i "s/127.0.0.1/${ip}/g" /etc/nginx/nginx.conf
#重要:给mysql的数据卷重新赋予mysql的用户权限,挂载之后的用户权限会变动
chown mysql:mysql -R /var/lib/mysql/
#启动数据库,并创建数据库
service mysql restart
sleep 2;
#准备数据库脚本(使用数据库,并解决乱码问题)
sed -i '1i\use `psms2.1`;set names utf8;' /opt/psms2.1.sql
MYSQL="mysql -uroot -p123456"
sql_i="GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;"
sql_j="flush privileges;"
#导入mysql数据
sql_creatTable="create DATABASE if not exists \`psms2.1\` DEFAULT CHARSET UTF8;"
#sql_dropDb="drop DATABASE if exists \`psms2.1\`;"
#sql_createDb="create DATABASE if not exists \`psms2.1\` DEFAULT CHARSET UTF8;"
sql_z="exit"
#修改远程登录权限
$MYSQL -e "${sql_i}"
$MYSQL -e "${sql_j}"
$MYSQL -e "${sql_z}"
#创建数据库,并导入数据
$MYSQL -e "${sql_creatTable}"
#判断是否第一次初始化psms2.1数据库数据,文件不存在,则执行sql脚本初始化数据库
if [ ! -f "/var/lib/mysql/psms2@002e1/sys_user.frm" ];then
echo "init psms2.1!"
$MYSQL -e "source /opt/psms2.1.sql"
fi
#$MYSQL -e "source /opt/psms2.1.sql"
$MYSQL -e "${sql_z}"
#修改前台代码配置
sed -i "s/localhost/${ip}/g" /opt/dist/static/config.js
#TODO 此处缺省配置视频源ip
#sys项目,8088相关配置
#启动tomcat,自动解压war包
/opt/tomcat-8088/bin/catalina.sh start
#等待sql执行完成,等待war包解压完成
sleep 60
#停止8088服务,以免后面修改文件失败,进程占用冲突
/opt/tomcat-8088/bin/catalina.sh stop
#将项目移动到tomcat/webapps/ROOT下
mv /opt/tomcat-8088/webapps/sihuaTech-SYS-Web/* /opt/tomcat-8088/webapps/ROOT
rm /opt/tomcat-8088/webapps/sihuaTech-SYS-Web.war
rm -r /opt/tomcat-8088/webapps/sihuaTech-SYS-Web
#修改sys项目的相关配置
sed -i 's/10.221.100.115/localhost/g' /opt/tomcat-8088/webapps/ROOT/WEB-INF/classes/config/jdbc.properties
sed -i 's/psms2.1_deploy/psms2.1/g' /opt/tomcat-8088/webapps/ROOT/WEB-INF/classes/config/jdbc.properties
sed -i 's/^file.wordCreateDir=.*$/file.wordCreateDir=\/opt\/dist\/static\/PSMSFile\/word/' /opt/tomcat-8088/webapps/ROOT/WEB-INF/classes/config/system.properties
sed -i 's/^file.uploadDir=.*$/file.uploadDir=\/opt\/upload/' /opt/tomcat-8088/webapps/ROOT/WEB-INF/classes/config/system.properties
#echo "\n"${ip}>> /opt/tomcat-8088/webapps/ROOT/WEB-INF/classes/csrfWhite.txt
sed -i '$a\'${ip}'' /opt/tomcat-8088/webapps/ROOT/WEB-INF/classes/csrfWhite.txt
#qlt项目,8091相关配置
#启动tomcat,自动解压war包
/opt/tomcat-8091/bin/catalina.sh start
#等待sql执行完成,等待war包解压完成
sleep 60
/opt/tomcat-8091/bin/catalina.sh stop
#将项目移动到tomcat/webapps/ROOT下
mv /opt/tomcat-8091/webapps/sihuaTech-Qlt-Web/* /opt/tomcat-8091/webapps/ROOT
rm /opt/tomcat-8091/webapps/sihuaTech-Qlt-Web.war
rm -r /opt/tomcat-8091/webapps/sihuaTech-Qlt-Web
#修改qlt项目的相关配置
sed -i 's/10.221.100.115/localhost/g' /opt/tomcat-8091/webapps/ROOT/WEB-INF/classes/config/jdbc.properties
sed -i 's/psms2.1_deploy/psms2.1/g' /opt/tomcat-8091/webapps/ROOT/WEB-INF/classes/config/jdbc.properties
sed -i '$a\'${ip}'' /opt/tomcat-8091/webapps/ROOT/WEB-INF/classes/csrfWhite.txt
#启动服务
service nginx restart
service redis-server restart
/opt/tomcat-8088/bin/catalina.sh start
/opt/tomcat-8091/bin/catalina.sh start
#保持容器处于任务状态,不然会自动结束容器生命周期
tail -f /opt/tomcat-8088/logs/catalina.out
while true; do sleep 1000; done
#tail -f /var/log/redis/redis-server.log
3)运行docker shell脚本参考:
#!/bin/bash
#自动部署入口脚本
#docker Registry地址
REGISTRY_URL=localhost:5000
#docker工作目录
DOCKERDIR=/opt/workspace/psmsDocker
#进入到docker工作目录
# cd /opt/workspace/psmsDocker
#查询ip并写入ip文件
ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:" |sed -n '2p' > ip
#检查并启动docker本地仓库容器
if docker ps -a|grep -i myRegistry;then
echo "myRegistry is running!"
else
docker run -d -p 5000:5000 -v /root/my_registry:/tmp/registry --name="myRegistry" registry
fi
#删除可能已启动的名为psms的容器
if docker ps -a|grep -i psms;then
docker rm -f psms
fi
#使用当前目录的Dockerfile创建镜像,命名为docker_psms
docker build -t $REGISTRY_URL/docker_psms .
#给镜像打上Tag
docker tag $REGISTRY_URL/docker_psms v1.0
#(此处需要先启动本地仓库容器,否则将显示connection failed)推送psms镜像到docker远程仓库
docker push $REGISTRY_URL/docker_psms
#启动tomcat容器,容器名为psms
docker run -it -d -p 8088:8088 -p 80:80 -p 3306:3306 -p 8091:8091 --name psms $REGISTRY_URL/docker_psms
#初始化主机挂载卷目录,从容器中拷贝mysql数据到宿主机
if [ ! -d "$DOCKERDIR/mysql" ];then
echo "$DOCKERDIR/mysql not exited"
docker cp psms:/var/lib/mysql $DOCKERDIR
fi
#删除容器,并挂载重新启动
docker rm -f psms
#TODO 重新启动psms,并设置自动重启规则
docker run -it -d --restart=always -p 8088:8088 -p 80:80 -p 3306:3306 -p 8091:8091 --name psms -v $DOCKERDIR/mysql:/var/lib/mysql $REGISTRY_URL/docker_psms
四、Docker进阶
1、三剑客:
1)docker-machine:
docker-machine就是docker公司官方提出的,用于在各种平台上快速创建具有docker服务的虚拟机的技术,甚至可以通过指定driver来定制虚拟机的实现原理(一般是virtualbox)。
2)docker-compose:
dcoker-compose技术,就是通过一个.yml配置文件,将所有的容器的部署方法、文件映射、容器连接等等一系列的配置写在一个配置文件里,最后只需要执行docker-compose up命令就会像执行脚本一样的去一个个安装容器并自动部署他们,极大的便利了复杂服务的部署。
3)docker-swarm:
swarm是基于docker平台实现的集群技术,他可以通过几条简单的指令快速的创建一个docker集群,接着在集群的共享网络上部署应用,最终实现分布式的服务。
相比起zookeeper等集群管理框架来说,swarm显得十分轻量,作为一个工具,它把节点的加入、管理、发现等复杂的操作都浓缩为几句简单的命令,并且具有自动发现节点和调度的算法,还支持自定制。虽然swarm技术现在还不是非常成熟,但其威力已经可见一般。
2、docker-compose详解:
1)安装docker-compose:
注意:安装Docker compose之前需要安装Docker!
1)运行此命令下载Docker组合的最新版本:
sudo curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
2)将可执行权限应用于二进制文件:
sudo chmod +x /usr/local/bin/docker-compose
3)测试安装:
docker-compose --version
4)启动命令:(进入workspace)
docker-compose up
2)docker-compose.yml文件内容参考:
version: '2'
# 这个version是指dockerfile解析时用的版本,不是给我们自己定义版本号用的.
services:
webapp_sys:
image: tomcat:8
container_name: sys # 容器名
depends_on:
- mysql
- redis
# - nginx
volumes:
- ./conf/tomcat_8088/server.xml:/usr/local/tomcat/conf/server.xml
- ./code/SYS:/usr/local/tomcat/webapps/ROOT
ports:
- "8088:8088"
restart: unless-stopped # 容器重启策略
networks:
- front-tier
webapp_qlt:
image: tomcat:8
container_name: qlt # 容器名
depends_on:
- mysql
- redis
# - nginx
volumes:
- ./conf/tomcat_8091/server.xml:/usr/local/tomcat/conf/server.xml
- ./code/Qlt:/usr/local/tomcat/webapps/ROOT
ports:
- "8091:8091"
restart: unless-stopped # 容器重启策略
networks:
- front-tier
redis:
image: redis
container_name: redis # 容器名
restart: unless-stopped # 容器重启策略
networks:
- front-tier
ports:
- "6379:6379"
nginx:
image: nginx
container_name: nginx # 容器名
restart: unless-stopped # 容器重启策略
ports:
- "80:80"
volumes:
- ./code/web:/opt
- ./conf/nginx.conf:/etc/nginx/nginx.conf
networks:
- front-tier
mysql:
build: ./mysql
container_name: mysql # 容器名
restart: unless-stopped # 容器重启策略
volumes:
- ./mysql/dbdata:/var/lib/mysql # 挂载数据到主机
- ./mysql/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf # 设置不区分大小写,屏蔽只允许本地ip访问
ports:
- "3306:3306"
environment:
MYSQL_USER: root
MYSQL_PASSWORD: 123456
MYSQL_ROOT_PASSWORD: 123456
networks:
- front-tier
networks:
front-tier:
driver: bridge
3)运行docker-compose脚本参考:
#!/bin/bash
#linux shell 脚本编写好要经过漫长的调试阶段,可以使用sh -x 执行
set -x
#查询ip并写入ip文件
ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:" |tail -n 1 > ip
#获取宿主机ip
ip=$(sed -r "s/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/\n\1/;s/^.*\n//" ./ip)
echo ${ip}
#war解压目录
SYSDIR=./code/SYS
QltDIR=./code/Qlt
#需要判断是否已经解压
if [ ! -f "$SYSDIR/index.jsp" ];then
unzip ./code/sihuaTech-SYS-Web.war -d $SYSDIR
else
echo "SYSDIR have been ziped!"
fi
if [ ! -d "$QltDIR/WEB-INF" ];then
unzip ./code/sihuaTech-Qlt-Web.war -d $QltDIR
else
echo "QltDIR have been ziped!"
fi
#修改sys项目的相关配置
#此处需要换成宿主机ip
sed -i 's/10.221.100.115/'${ip}'/g' $SYSDIR/WEB-INF/classes/config/jdbc.properties
# redis需要换成宿主机ip,所以需要暴露端口
sed -i "s/127.0.0.1/${ip}/g" $SYSDIR/WEB-INF/classes/config/system.properties
sed -i 's/psms2.1_deploy/psms2.1/g' $SYSDIR/WEB-INF/classes/config/jdbc.properties
sed -i 's/^file.wordCreateDir=.*$/file.wordCreateDir=\/opt\/dist\/static\/PSMSFile\/word/' $SYSDIR/WEB-INF/classes/config/system.properties
sed -i 's/^file.uploadDir=.*$/file.uploadDir=\/opt\/upload/' $SYSDIR/WEB-INF/classes/config/system.properties
sed -i '$a\'${ip}'' $SYSDIR/WEB-INF/classes/csrfWhite.txt
#nginx容器跨域请求
#sed -i '$a\172.19.0.233' $SYSDIR/WEB-INF/classes/csrfWhite.txt
#修改qlt项目的相关配置
#此处需要换成宿主机ip
sed -i 's/10.221.100.115/'${ip}'/g' $QltDIR/WEB-INF/classes/config/jdbc.properties
# redis需要换成宿主机ip,所以需要暴露端口
sed -i "s/127.0.0.1/${ip}/g" $QltDIR/WEB-INF/classes/config/system.properties
sed -i 's/psms2.1_deploy/psms2.1/g' $QltDIR/WEB-INF/classes/config/jdbc.properties
sed -i '$a\'${ip}'' $QltDIR/WEB-INF/classes/csrfWhite.txt
#nginx跨域请求
#sed -i '$a\172.19.0.233' $QltDIR/WEB-INF/classes/csrfWhite.txt
echo "后台配置完成!"
#修改前台的相关配置
#修改nginx配置:代理ip
sed -i "s/127.0.0.1/${ip}/g" ./conf/nginx.conf
sed -i "s/localhost/${ip}/g" ./code/web/dist/static/config.js
#TODO 此处缺省配置视频源ip
echo "前台配置完成!"
#拉去依赖的所有镜像
docker-compose pull
docker-compose build
#启动docker compose
#使用 --force-recreate 可以强 制重建容器 (否则只能在容器配置有更改时才会重建容器)
docker-compose up -d --force-recreate
4)docker-compose常用命令:
docker-compose up 启动docker-compose项目;
docker-compose logs 查看日志;
docker-compose exec container_name bash 进入到compose里面的某个容器;
docker-compose stop 停止docker-compose;
五、遇到问题及解决办法:
1、docker pull镜像超时:(切换国内镜像)
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://ef017c13.m.daocloud.io
然后再重启:
systemctl restart docker
参考网址: