Mingo

Docker 容器使用
什么是 DockerDocker是一个使用 Go 语言开发的,并且开源的应用容器引擎,基于LXC(Linux Co...
扫描右侧二维码阅读全文
06
2019/07

Docker 容器使用

什么是 Docker

Docker是一个使用 Go 语言开发的,并且开源的应用容器引擎,基于LXC(Linux Container)内核虚拟化技术实现,提供一系列更强的功能,比如镜像、Dockerfile等;

Docker理念是将应用及依赖包打包到一个可移植的容器中,可发布到任意Linux发行版的Docker引擎上,使用沙箱机制运行程序,程序之间相互隔离;

Docker采用C/S架构,Dcoker daemon作为服务端接受来自客户端请求,并处理这些请求,比如创建、运行容器等;客户端为用户提供一系列指令与Docker Daemon交互;
Docker架构与内部组件

LXC:Linux容器技术,共享内核,宿主机资源,使用NameSpace和Cgroups对资源限制与隔离;

Cgroups(control groups):Linux内核提供的一种限制单进程或者多进程资源的机制;比如CPU、内存等资源的使用限制;

NameSpace:命名空间,也称名字空间,Linux内核提供的一种限制单进程或者多进程资源隔离机制;一个进程可以属于多个命名空间;Linux内核提供了六种NameSpace:UTS、IPC、PID、Network、Mount和User。

AUFS(advanced multi layered unification filesystem):高级多层统一文件系统,是UFS的一种,每个branch可以指定readonly(ro只读)、readwrite(读写)和whiteout-able(wo隐藏)权限;一般情况下,aufs只有最上层的branch才有读写权限,其他branch均为只读权限。

UFS(UnionFS):联合文件系统,支持将不同位置的目录挂载到同一虚拟文件系统,形成一种分层的模型;成员目录称为虚拟文件系统的一个分支(branch);
Docker 内部结构

Docker 优点与虚拟机的区别

  • 持续集成
    在项目快速迭代情况下,轻量级容器对项目快速构建、环境打包、发布等流程就能提高工作效率;
  • 版本控制
    每个镜像就是一个版本,在一个项目多个版本时可以很方便管理;
  • 可移植性
    容器可以移动到任意一台Linux的Docker引擎上,而不需要过多关注底层系统;
  • 标准化
    应用程序环境及依赖、操作系统等问题,增加了生产环境故障率,容器保证了所有配置、依赖始终不变;
  • 隔离性与安全
    容器之间的进程是相互隔离的,一个容器出现问题不会影响其他容器;

VMware VS Docker

以KVM举例,与Docker对比
Ø 启动时间
Docker是秒级启动,而KVM是分钟级;
Ø 轻量级
容器镜像大小通常以M为单位,而虚拟机以G为单位;容器资源占用小,要比虚拟机部署更快速;
Ø 性能
容器共享宿主机内核,系统级虚拟化,占用资源少,没有Hypervisor层开销,容器性能基本接近物理机;而虚拟机需要Hypervisor层支持,虚拟化一些设备,具有完整的GuestOS,虚拟化开销大,因而降低性能,没有容器性能好;
Ø 安全性
由于共享宿主机内核,只是进程级隔离,因此隔离性和稳定性不如虚拟机,容器具有一定权限访问宿主机内核,存在一定安全隐患,在这一点上可能就是Doker唯一比不上的吧.....
Ø 使用要求
KVM基于硬件的完全虚拟化,需要硬件CPU虚拟化技术支持;容器共享宿主机内核,可运行在主流的Linux发行版,不用考虑CPU是否支持虚拟化技术;

应用场景

Ø 应用打包与部署自动化
构建标准化的运行环境;现在大多方案是在物理机和虚拟机上部署运行环境,面临问题是环境杂乱、完整性迁移难度高等问题,容器即开即用;

Ø 自动化测试和持续集成/部署
自动化构建镜像和良好的REST API,能够很好的集成到持续集成/部署环境来;

Ø 部署与弹性扩展
由于容器是应用级的,资源占用小,弹性扩展部署速度要更快;

Ø 微服务
Docker这种容器华隔离技术,正式应对了微服务理念,将业务模块放到容器中运行,容器的可复用性大大增加了业务模块扩展性;

Docker 的安装

# 安装依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加Docker软件包源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 更新yum包索引
yum makecache fast
# 安装Docker CE
yum install docker-ce

# 启动
systemctl start docker
# 测试
docker run hello-world
docker version
# 卸载
yum remove docker-ce
rm -rf /var/lib/docker

Centos6对于Docker的官方支持理论上来说只能算是勉强能用,因为只提供了基于1.7.1版本的docker-io,还得先装EPEL源,然而1.7.1版本很多功能都有缺失,至少到1.9才能算够用,具体解决方案:传送门

Docker 镜像

Docker 镜像是一个不包含Linux内核而又精简的Linux操作系统

Docker Hub公共镜像库:https://hub.docker.com/search/?q=&type=image

镜像工作原理
当我们启动一个新的容器时,Docker会加载只读镜像,并在其之上添加一个读写层,并将镜像中的目录复制一份到/var/lib/docker/aufs/mnt/容器ID目录下,我们可以使用chroot进入此目录,如果运行中的容器修改一个已经存在的文件,那么会将该文件从下面的只读层复制到读写层,只读层的这个文件就会覆盖,但还存在,这就实现了文件系统隔离,当删除容器后,读写层的数据将会删除,只读镜像不变;

镜像文件存储结构
Docker相关文件存放在:/var/lib/docker
/var/lib/docker/aufs/diff目录下是每层与其父层之间的文件差异;

/var/lib/docker/aufs/layers/目录下是每层一个文件,记录其父层一直到根层之间的ID,大部分文件的最后一行都已,表示继承来自同一层;

/var/lib/docker/aufs/mnt目录下是联合挂载点,从只读层复制到最上层可读写层的文件系统数据在建立镜像时,每次写操作,都被视作一种增量操作,即在原有的数据层上添加一个新层;所以一个镜像会有若干个层组成;每次commit提交就会对产生一个ID,就相当于在上一层有加了一层,可以通过这个ID对镜像回滚;

镜像管理的相关命令

#模糊查询镜像库的镜像,docker search [镜像名称]
docker search centos

#下载镜像库的镜像,docker pull [镜像名称]
docker pull centos    

#查询本地的镜像信息,docker images
docker images

#将修改的内容保存为一个新的镜像,docker commit [容器名] [镜像名]{:[标签]}
docker commit test centos:self 

#删除本地镜像,docker rmi [镜像名]{:[标签]}
docker rmi mysql

#导出容器的文件系统生成一个tar包,docker export [容器名] > [导出保存的路径]
docker export test_self_image > test_self_image.tar

#将tar包导入到本地镜像,docker import [tar包名] [镜像名]{:[标签]}
docker import test_self_image.tar centos:v1.0.0

#将镜像导出为tar包,docker save [镜像名]{:[标签]}
docker save nginx > nginx.tar

#将tar包导入到本地镜像库,docker load -i [tar包名]
docker load -i nginx.tar

docker save保存的是镜像(image)
docker export保存的是容器(container)

Docker 容器管理的相关命令

创建容器命令格式:

docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Options(常用选项):

-i,--interactive:标准输入;
-t,--tty:分配伪终端;
-d,--detach:容器到后台运行;

--add-host list:添加hosts解析;
--cap-add list:添加内核访问控制权限;
--cap-drop list:去除内核访问控制权限;
--cidfile string:容器ID写入到PID文件路径;
--device list:添加宿主的设备到容器;
--dns list:指定dns解析服务器地址;
-e,--env list:设置变量到容器中;
--env-file list:指定变量文件路径;
--expose list:申明容器提供的端口;
-h,--hostname string:设置容器主机名;
--ip string:设置容器主机IP地址;
--log-driver:指定容器日志格式(none、json-file、syslog、fluentd、splunk);
--network string:连接容器到指定网络;
--oom-kill-disable:禁用自动检测进程资源占用过大而kill掉该容器;
-p,--publish list:端口映射;
--restart:尝试重新启动,比如--restart on-failure:3挂掉后尝试重启3次;
--ulimit ulimit:设定最大进程数和最大文件打开数;
-w,--workdir string:进入容器后所在的工作目录;
-m,--memory:硬限制容器运行所使用的最大内存值;
--memory-reservation bytes:软限制容器运行所使用的最大内存值;
--memory-swappiness int:设置是否使用Swap交换内存;

#查看容器
docker ps -als
#进入一个容器,docker attach [容器名]
docker attach mydocker
或
docker exec -it mydocker /bin/bash
#删除容器,docker rm [容器名],加上-f 选项则表示强制删除
docker rm mydocker
#启动容器,docker start [容器名]
docker start mydocker
#停止容器,docker stop [容器名]
docker stop mydocker
#杀死容器进程docker kill [容器名]
docker kill mydocker
#挂起容器,docker pause/unpause [容器名]
docker pause mydocker
docker unpause mydocker
#重命名容器,docker rename [原容器名] [新容器名]
docker rename mydocker idocker

#查看容器所有信息,docker inspect [容器名]
docker inspect idocker
#容器中执行命令,docker exec [容器名] [命令]
docker exec idocker ls /home/
#查看容器中运行的进程,docker top [容器名]
docker top idocker
#查看容器的端口映射,docker port [容器名]
docker port idocker
#拷贝文件,docker cp [拷贝的文件] [存放的位置]
docker cp pass.txt idocker:/home
docker cp idocker:/home/pass.txt /tmp/pass_idocker.txt
#查看容器自启动后的变更,docker diff [容器名]
docker diff idocker
#查看容器标准输出日志,docker logs [容器名]
docker logs idocker
#动态查看容器利用率,docker stats [容器名],加上--no-stream选项则表示输出一次
docker stats idocker
#及时修改跟新容器配置,docker update [容器名]
docker update idocker
#查看Docker主机事件
docker events

删除所有容器:docker rm -f $(docker ps -q -a)

容器数据持久化

数据卷

将宿主机目录挂载到容器目录

数据卷特点:
Ø 在容器启动初始化时,如果容器使用的宿主机挂载点有数据,这些数据就会拷贝到容器中。
Ø 数据卷可以在容器直接共享和重用。
Ø 可以直接对数据卷里的内容进行修改。
Ø 数据卷的变化不会影响镜像的更新。
Ø 卷会一直存在,即使挂载数据卷的容器已经删除。

示例:
docker run -itd --name docker_web -v /container_data/web:/data centos

/container_data/web为宿主机目录,/data是容器中目录,目录不存在会自动创建

容器数据卷

将一个运行的容器作为数据卷,让其他容器通过挂载这个容器实现数据共享。
示例:
docker run -itd -v /data --name docker_data centos
docker run -itd --name docker_web --volumes-from docker_data centos

搭建WoedPress LNMP Docker

# 创建mysql数据库容器
docker run -itd --name mysql -p 3333:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql --character-set-server=utf8
# 创建wp数据库
docker exec mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e"create database wp"'
#查看数据库是否创建成功
docker exec mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e"show databases;"'
# 创建PHP环境容器
docker run -itd --name web --link mysql:db -p 8080:80 -v /container_data/web:/app webdevops/php-nginx
# 以wordpress博客为例测试
wget https://cn.wordpress.org/wordpress-4.7.4-zh_CN.tar.gz
tar zxf wordpress-4.7.4-zh_CN.tar.gz
mv wordpress/* /container_data/web/

浏览器测试访问
http://IP:8080
PHPinfo

Docker 网络

网络模式

先创建一个docker0的网桥,使用veth pair创建一对虚拟网卡,一端放到新创建的容器中,并重命名eth0,另一端放到宿主机上,以veth+随机7个字符串命名,并将这个网络设备加入到docker0网桥中,网桥自动为容器分配一个IP,并设置docker0的IP为容器默认网关;所以容器默认网络都加入了这个网桥,因此都可以彼此通信;同时在iptables添加SNAT转换网络段IP,以便容器访问外网;

Docker 主机默认网络

Ø bridge
默认网络,Docker启动后创建一个docker0网桥,默认创建的容器也是添加到这个网桥中;IP地址段是172.17.0.1/16;

Ø host
容器不会获得一个独立的network namespace,而是与宿主机共用一个;

Ø none
获取独立的network namespace,但不为容器进行任何网络配置;

Ø container
与指定的容器使用同一个network namespace,网卡配置也都是相同的;

Ø 自定义
自定义网桥,默认与bridge网络一样;

容器网络访问原理

Docker主要通过Netfilter/Iptables实现网络通信;iptables由netfilter和iptables组成,Netfilter组件是Linux内核集成的信息包过滤系统,它维护一个信息包过滤表,这个表用于控制信息包过滤处理的规则集;而Iptables只是一个在用户空间的工具,用于增删改查这个过滤表的规则;

iptables 对应关系表

数据转发流图

容器访问外部

[root@docker ~]# iptables -t nat -nL
Chain POSTROUTING (policy ACCEPT)
target      prot opt source          destination         
MASQUERADE  all  --  172.17.0.0/16   0.0.0.0/0                  
MASQUERADE  tcp  --  172.17.0.3      172.17.0.3   tcp dpt:33060
MASQUERADE  tcp  --  172.17.0.4      172.17.0.4   tcp dpt:80

外部访问容器

[root@docker ~]# iptables -t nat -nL
Chain DOCKER (2 references)
target  prot opt source      destination              
DNAT    tcp  --  0.0.0.0/0   0.0.0.0/0   tcp dpt:3333 to:172.17.0.3:33060
DNAT    tcp  --  0.0.0.0/0   0.0.0.0/0   tcp dpt:8080 to:172.17.0.4:80

桥接宿主机网络与配置固定IP

桥接宿主机网络

#关掉docker0
ifconfig docker0 down
#删除docker
brctl  delbr  docker0
#增加网桥br0
yum install bridge-utils   

#配置网桥
vim /etc/sysconfig/network-scripts/ifcfg-br0
TYPE=Bridge
DEVICE=br0
BOOTPROTO=static
ONBOOT=yes
IPADDR=192.168.0.152
NETMASK=255.255.255.0
GATEWAY=192.168.0.1
DNS1=8.8.8.8

#配置网卡
vim /etc/sysconfig/network-scripts/ifcfg-eno16777736
TYPE="Ethernet"
DEVICE="eno16777736"
NAME="eno16777736"
BOOTPROTO="none"
ONBOOT="yes"
BRIDGE="br0"

#重启网络
systemctl restart network

#查看物理机上有哪些网桥
brctl show
bridge name  bridge id           STP enabled  interfaces
br0          8000.000c2984bb70   no           eno16777736

配置Docker桥接网络

#方案一:自定义脚本 docker_auto.sh

vim docker_auto.sh
read -p "Please Enter Your Docker Name:" dockername
read -p "Please Enter Your Docker Image Name:" dkimg
read -p "Please Enter Your Docker IP Address:" dockerip
read -p "Please Enter Your Docker IP GW:" dockergw
read -p "Please Enter Your Network BG Name:" bgname

#配置固定IP
C_ID=$(docker run -itd --net=none --name ${dockername} ${dkimg})
C_PID=$(docker inspect -f '{{.State.Pid}}' $C_ID)
# 创建network namespace目录并将容器的network namespace软连接到此目录,以便ip netns命令读取
mkdir -p /var/run/netns
ln -s /proc/$C_PID/ns/net /var/run/netns/$C_PID
# 添加虚拟网卡veth+容器PID,类型是veth pair,名称是vp+容器PID
ip link add veth$C_PID type veth peer name vp$C_PID
# 添加虚拟网卡到br0网桥
brctl addif $bgname veth$C_PID
# 激活虚拟网卡
ip link set veth$C_PID up
# 给进程配置一个network namespace
ip link set vp$C_PID netns $C_PID
# 在容器进程里面设置网卡信息
ip netns exec $C_PID ip link set dev vp$C_PID name eth0
ip netns exec $C_PID ip link set eth0 up
ip netns exec $C_PID ip addr add ${dockerip}/24 dev eth0
ip netns exec $C_PID ip route add default via $dockergw

echo $dockername $dkimg $dockerip $dockergw $bgname $C_ID $C_PID

#方案二:使用pipework工具
git clone https://github.com/jpetazzo/pipework.git
cp pipework/pipework /usr/local/bin/
docker run -itd --net=none --name idocker2 centos
pipework br0 idocker2 192.168.0.88/24@192.168.0.1

容器SSH连接

docker run -itd --name idocker3 centos
docker attach idocker3
yum install openssh-server
passwd root
docker commit idocker3 centos_ssh
docker run -itd --name idocker3 -p 2222:22 centos_ssh

Docker File

常用命令

指令描述
FROM构建的新镜像是基于哪个镜像;
例如:FROM centos:6
MAINTAINER镜像维护者姓名或邮箱地址;
例如:MAINTAINER lizhenliang
RUN构建镜像时运行的Shell命令
例如:RUN [“yum”, “install”, “httpd”]
RUN yum install httpd
CMD运行容器时执行的Shell命令;
例如:CMD [“-c”, “/start.sh”]
CMD ["/usr/sbin/sshd", "-D"]
CMD /usr/sbin/sshd –D
EXPOSE声明容器运行的服务端口;
例如:EXPOSE 80 443
ENV设置容器内环境变量;
例如:ENV MYSQL_ROOT_PASSWORD 123456
ADD拷贝文件或目录到镜像,如果是URL或压缩包会自动下载或自动解压
ADD <src>… <dest>
ADD [“<src>”,… “<dest>”]
ADD https://xxx.com/html.tar.gz /var/www/html
ADD html.tar.gz /var/www/html
COPY拷贝文件或目录到镜像,用法同上;
例如:COPY ./start.sh /start.sh
ENTRYPOINT运行容器时执行的Shell命令;
例如:ENTRYPOINT [“/bin/bash", “-c", “/start.sh"]
ENTRYPOINT /bin/bash -c ‘/start.sh’
VOLUME指定容器挂载点到宿主机自动生成的目录或其他容器;
例如:VOLUME ["/var/lib/mysql"]
USER为RUN、CMD和ENTRYPOINT执行命令指定运行用户
USER <user>[:<group>] or USER <UID>[:<GID>]
例如:USER lizhenliang
WORKDIR为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录;
例如:WORKDIR /data
HEALTHCHECK健康检查;
HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ exit 1
ARG在构建镜像时指定一些参数;
例如:FROM centos:6
ARG user # ARG user=root USER $user
# docker build --build-arg user=lizhenliang Dockerfile.

RUN、CMD和ENTRYPOINT指令区别
1.RUN在building时运行,可以写多条;
2.CMD和ENTRYPOINT在运行container时运行,只能写一条,如果写多条,最后一条生效;
3.CMD在run时可以被COMMAND覆盖,ENTRYPOINT不会被COMMAND覆盖,但可以指定—entrypoint覆盖;

Build镜像构建

使用Dockerfile文件构建镜像

Usage: docker build [OPTIONS] PATH | URL | -
Options:
-t, --tag list # 镜像名称
-f, --file string # 指定Dockerfile文件位置

示例:
docker build . # 默认找当前目录以Dockerfile为命名的文件
docker build -t shykes/myapp .
docker build -t shykes/myapp -f /path/Dockerfile /path
docker build -t shykes/myapp - < Dockerfile
docker build -t shykes/myapp - < context.tar.gz
docker build -t shykes/myapp http://www.example.com/Dockerfile
docker build -f shykes/myapp http://www.example.com/contex.tar.gz

构建 PHP 网站环境镜像

#Dockerfiler文件配置
FROM centos:6
MAINTAINER Mingo
RUN yum install -y httpd php php-gd php-mysql mysql mysql-server
ENV MYSQL_ROOT_PASSWORD 123456
RUN echo "<?php phpinfo(); ?>" > /var/www/html/index.php
COPY start.sh /start.sh
RUN chmod +x /start.sh
ADD https://cn.wordpress.org/wordpress-4.7.4-zh_CN.tar.gz /var/www/html
COPY wp-config.php /var/www/html/wordpress
VOLUME ["/var/lib/mysql"]
CMD /start.sh
EXPOSE 80 3306

vim start.sh
service httpd start
service mysqld start
mysqladmin -uroot password $MYSQL_ROOT_PASSWORD
tail -f

构建 JAVA 网站环境镜像

FROM centos:6
MAINTAINER Mingo
COPY jdk-8u45-linux-x64.tar.gz /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_45
ADD http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.0.45/bin/apache-
tomcat-8.0.45.tar.gz /usr/local
WORKDIR /usr/local/apache-tomcat-8.0.45
ENTRYPOINT ["bin/catalina.sh", "run"]
EXPOSE 8080

构建支持 SSH 服务镜像

FROM centos:6
MAINTAINER Mingo
ENV ROOT_PASSWORD 123456
RUN yum install -y openssh-server
RUN echo $ROOT_PASSWORD |passwd --stdin root
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
CMD ["/usr/sbin/sshd", "-D"]
EXPOSE 22
Last modification:September 29th, 2019 at 06:36 am

Leave a Comment