文章

Docker容器技术入门与进阶实战学习笔记

Docker容器技术入门与进阶实战学习笔记

本文档介绍 Docker容器技术入门与进阶实战学习笔记 的相关内容。

分配一个伪终端

docker run -i -t centos /bin/bash docker run -it centos /bin/bash # 如果镜像不存在,会自动去官方下载

安装docker环境

参考官方文档:docs.docker.com

https://docs.docker.com/install/linux/docker-ce/centos/

安装依赖包

yum install -y yum-utils device-mapper-persistent-data lvm2

安装docker-ce源

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安装docker

yum install -y docker-ce

设置开机启动并启动docker

systemctl enable docker systemctl start docker

测试docker

docker run hello-world

查看docker详细信息

docker info

查看docker版本信息

docker version

创建一个容器(自动下载一个容器)

docker run -it nginx

查看容器信息(查看ip信息)

docker inspect <ID/NAME>

进入容器

docker exec -it <ID/NAME> /bin/bash

运行并进入容器

docker run -it <ID/NAME> /bin/bash

查看容器资源限制

docker stats <ID/NAME> docker ststs --no-stream <ID/NAME> # 查看CPU限制

强制删除正在运行的容器

docker rm -f $(docker ps -a |awk '{print $1}')

测试镜像:

docker run -it busybox # 测试用镜像

镜像是什么:

  • 一个分层存储的文件
  • 一个软件的环境
  • 一个镜像可以创建N个容器
  • 一个标准化的交付方式
  • 一个不包含Linux内核而又精简的Linux操作系统
    镜像不是一个单一的文件,而是有多层构成。我们可以通过docker history <ID/NAME> 查看镜像中各层内容及大小,每层对应着Dockerfile中的一条指令。Docker镜像默认存储在/var/lib/docker/\<storage-driver\> 中。 查看镜像有哪些分层
docker history nginx

检索镜像

docker search nginx

配置镜像加速

# https://www.daocloud.io/mirror curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io # cat /etc/docker/daemon.json { "registry-mirrors": ["http://f1361db2.m.daocloud.io"] } # 配置完成后重启docker systemctl restart docker

下载一个镜像

docker pull centos

镜像与容器的联系

如图,容器其实是在镜像的最上面加了一层读写层,在运行容器里文件改动时,会先从镜像里要写的文件复制到容器自己的文件系统中(读写层)。

如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。所以无论多少个容器共享一个镜像,所做的写操作都是从镜像的文件系统中复制过来操作的,并不会修改镜像的源文件,这种方式提高磁盘的利用率。

若想持久化这些改动。可以通过docker commit将容器保存成一个新镜像

镜像管理

管理镜像常用命令

docker image COMMAND

指令描述
ls列出镜像
build构建镜像来自Dockerfile
history查看镜像历史
inspect显示一个或多个镜像详细信息
pull从镜像创建拉取镜像
push推送一个镜像到镜像仓库
rm移除一个或多个镜像
prune移除未使用的镜像。没有被标记或被任何容器引用的
tag创建一个引用源镜像标记目标镜像
export导出容器文件系统到tar归档文件
import导入容器文件系统tar归档文件创建镜像
save保存一个或多个镜像到一个tar归档文件
load加载镜像来自tar归档或标准输入

保存一个镜像,完整导出

docker image save nginx > nginx.tar

加载导入一个镜像

docker image load < nginx.tar

容器管理

管理容器的常用命令

docker container run COMMAND

docker run COMMAND # 老的命令

选项描述
- i, -interactive交互式
- t, -tty分配一个伪终端
- d, -detach运行容器到后台
- e, -env设置环境变量
- p, -publish list发布容器端口到主机
- P, -publish-all发布容器所有EXPOSE的端口到宿主机随机端口
- name string指定容器名称
- h, -hostname设置容器主机名
- ip, string指定容器ip, 只能用于自定义网络
- network连接容器到一个网络
- mount mount将文件系统附加到容器
- v, -volume list绑定挂载一个卷
- restart string容器退出时重启策略,默认no, 可选值:[always(开机启动) \

限制容器资源的常用命令

docker container run COMMAND

选项描述
- m, -memory容器可以使用的最大内存量
- memory-swap允许交换到磁盘的内存量
- memory-swappiness=<0-100>容器使用SWAP分区交换的百分比(0-100, 默认为-1)
- oom-kill-disable禁用OOM Killer
- cpus可以使用的CPU数量
- cpuset-cpus限制容器使用特定的CPU核心,如(0-3,0,1)
- cpu-sharesCPU共享(相对权重)

示例:

内存限额:

允许容器最多使用500M内存和100Mswap,并禁用OOM Killer:

docker run -d --name nginx --memory="500m" --memory-swap="600m" --oom-kill-disable nginx

不设置Swap,将memory、memory-swap 的值设置为一样

docker run -d --name nginx --memory="500m" --memory-swap="500m" --oom-kill-disable nginx

CPU限额:

允许容器最多使用1个半的CPU:

docker run -d --name nginx --cpus="1.5" nginx

允许容器最多使用50%的CPU:

docker run -d --name nginx --cpus=".5" nginx

查看管理容器的常用命令

选项描述
ls列出容器
inspect查看一个或多个容器详细信息
exec在运行容器中执行命令
commit创建一个新镜像来自一个容器
cp拷贝文件/文件夹到一个容器
logs获取一个容器日志
port列出或指定容器端口映射
top显示一个容器运行的进程
stats显示容器资源使用统计
stop/start停止/启动一个或多个容器
rm删除一个或多个容器

列出刚创建的容器

docker ps -l

列出所有容器

docker ps -a

管理应用程序数据

将数据从宿主机挂载到容器的三种方式

Docker 提供三种方式将数据从宿主机挂载到容器中

  • volumes: Docker 管理宿主机文件系统的一部分/var/lib/docker/volumes。保存数据的最佳方式。
  • bind mounts: 将宿主机上的任意位置的文件或目录挂载到容器中
  • tmpfs: 挂载存储在主机系统内存中,而不会写入主机的文件系统。如果不希望数据持久存储在任何位置,可以使用tmpfs,同时避免写入容器可写层提供高性能。

Volume

管理卷

docker volume create nginx-vol docker volume ls docker volume inspect nginx-vol

用卷创建一个容器

docker run -d -it --name=nginx-test --mount src=nginx-vol,dst=/usr/share/nginx/html nginx docker run -d -it --name=nginx-test -v nginx-vol:/usr/share/nginx/html nginx

清理

docker stop nginx-test docker rm nginx-test docker volume rm nginx-vol

注意:

  1. 如果没有指定卷,自动创建。
  2. 建议使用 --mount, 更通用。

Bind Mounts

用卷创建一个容器

docker run -d -it --name=nginx-test --mount type=bind,src=/app/wwwroot,dst=/usr/share/nginx/html nginx docker run -d -it --name=nginx-test -v /app/wwwroot:/usr/share/nginx/html nginx

验证绑定

docker inspect nginx-test

清理

docker stop nginx-test docker rm nginx-test

注意:

  1. 如果源文件/目录没有存在,不会自动创建,会抛出一个错误
  2. 如果挂载目标在容器中非空目录,则该目录现有内容将被影藏

总结:

Volume 特点:

  • 多个运行容器之间共享数据。
  • 当容器停止或被移除时,该卷依然存在
  • 多个容器可以同时挂载相同的卷
  • 当明确删除时,卷才会被删除
  • 将容器的数据存储在远程主机或其它存储上
  • 将数据从一台Docker主机迁移到另一台时,先停止容器,然后备份卷的目录/var/lib/docker/volumes/

Bind Mounts特点:

  • 从主机共享配置文件到容器。默认情况下,挂载主机/etc/resolv.conf到每个容器,提供DNS解析
  • 在Docker主机上的开发环境和容器之间共享源代码。例如,可以将maven target目录挂载到容器中,每次在Doeker主机上构建maven项目时,容器都可以访问构建的项目包。
  • 当Docker主机的文件或目录结构保证与容器所需的绑定挂载一致时

容器网络

网络模式

  • bridge:
  • net = bridge
    默认网络,Docker启动后创建一个Docker0网桥,默认创建的容器也是添加到这个网桥中

  • host:
  • net = host
    容器不会获得一个独立的network namespace, 而是与宿主机共用一个。这就意味着容器不会有自己的网卡信息,而是使用宿主机的。容器除了网络,其它都是隔离的

  • none
  • net = none
    获取独立的network namespace, 但不为容器进行任何网络配置,需要我们手动配置

  • container
  • net = container:Name/ID
    与指定的容器使用同一个network namespace, 具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的

  • 自定义网络
    与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名或者主机名容器之间网络通信

容器到外部请求

外部到容器请求

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

临时生效

# 网桥名称 br_name=br0 # 添加网桥 brctl addbr $br_name # 给网桥设置ip ip addr add 192.168.1.120/24 dev $br_name # 删除已存在的eth0网卡配置 ip addr del 192.168.1.120/24 dev eth0 # 激动网桥 ip link set $br_name up # 添加eth0到网桥 brctl addif $br_name eth0 # 添加路由 ip route add default via 192.168.1.1 dev br0

还需要在Docker启动时桥接这个网桥:

# vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -b=br0 # systemctl daemon-reload # systemctl restart docker

永久生效

# vim /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 TYPE=Ethernet ONBOOT=yes BRIDGE=br0 # vim /etc/sysconfig/network-scripts/ifcfg-br0 DEVICE=br0 TYPE=Bridge ONBOOT=yes BOOTPROTO=static IPADDR=192.168.1.120 NETMASK=1.2.3.4 GATEWAY=192.168.1.1 DNS1=1.2.3.4

配置固定IP

C_ID=$(docker run -itd --name=none ubuntu) C_PID=$(docker inspect -f '{{.State.Pid}}' $C_ID) # 创建network namespace目录并将容器的network namespace软连接到些目录,以便ip netns命令读取 mkdir -p /var/run/netns ls -n /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 br0 veth$C_PID # 激活虚拟网卡 ip link set veth$C_PID up # 设置容器网络信息 IP='192.168.1.124/24' GW='192.168.1.1' # 给进程配置一个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 $IP dev eth0 ip netns exec $C_PID ip route add default via 192.168.1.1

pipework工具配置容器固定ip

git clone https://github.com/jpetazzo/pipework.git cp pipework/pipework /usr/local/bin docker run -itd --net=none --name test1 ubuntu pipework br0 test1 192.168.1.122/24@192.168.1.1

镜像制作Dockerfile

Dockerfile 介绍

基本格式

FROM centos:latest MAINTAINER jeff RUN yum install gcc -y COPY run.sh /usr/bin EXPOSE 80 CMD ["run.sh"]

Dockerfile常用指令 | 指令 | 描述 | | — | — | | FROM | 构建新镜像是基于哪个镜像 | | MAINTAINER | 镜像维护者姓名或邮箱地址 | | RUN | 构建镜像时运行的shell命令 | | COPY | 拷贝文件或目录到镜像中 | | ENV | 设置环境变量 | | USER | 为RUN、CMD和ENTRYPOINT执行命令指定运行用户 | | EXPOSE | 声明容器运行的服务端口 | | HEALTHCHECK | 容器中服务健康检查 | | WORKDIR | 为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录 | | ENTRYPOINT | 运行容器时执行,如果有多个ENTRYPOINT指令,最后一个生效 | | CMD | 运行容器时执行,如果有多个CMD指令,最后一个生效 |

Build镜像

Usage: docker build [OPTIONS] PATH | URL | - [flags] Options: t, --tag list # 镜像名称 f, --file string # 指定Dockerfile文件位置 # docker build . # docker build -t jeff/myapp . # docker build -t jeff/myapp -f /path/Dockerfile /path # docker build -t jeff/myall http://www.example.com/Dockerfile

构建Nginx基础镜像

步骤:

  1. yum或者源码编译安装(1. configure 2. make 3. make install) RUN
  2. 启用哪些模块 RUN
  3. nginx 初始化 RUN
  4. 启动 CMD ENTRIPOINT

Dockerfile-nginx

FROM centos:7 RUN yum install -y gcc gcc-c++ make \ openssl-devel pcre-devel gd-devel \ iproute net-tools telnet wget curl && \ yum clean all && \ rm -rf /var/cache/yum/* RUN wget http://nginx.org/download/nginx-1.15.5.tar.gz && \ tar zxf nginx-1.15.5.tar.gz && \ cd nginx-1.15.5 && \ ./configure --prefix=/usr/local/nginx \ -with-http_ssl_module \ -with-http_stub_status_module && \ make -j 4 && make install && \ rm -rf /usr/local/nginx/html/* && \ echo "ok" >> /usr/local/nginx/html/status.html && \ cd / && rm -rf nginx-1.15.5* && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ENV PATH $PATH:/usr/local/nginx/sbin COPY nginx.conf /usr/local/nginx/conf/nginx.conf WORKDIR /usr/local/nginx EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] # docker build -t nginx:v1 -f Dockerfile-nginx .

Dockerfile-php

FROM centos:7 MAINTAINER xsbloc.com RUN yum install -y epel-release -y && \ yum install -y gcc gcc-c++ make gd-devel libxml2-devlel \ libcurl-devel libjpeg-devel libpng-devel openssl-devel \ libmcrypt-devel libxslt-devel libtidy-devel autoconf \ iproute net-tools telnet wget curl && \ yum clean all && \ rm -rf /var/cache/yum* RUN wget http://docs.php.net/distributions/php-5.6.36.tar.gz && \ tar zxf php-5.6.36.tar.gz && \ cd php-5.6.36 && \ ./configure --prefix=/usr/local/php \ -with-config-file-path=/usr/local/php/etc \ -enable-fpm --enable-opcache \ -with-mysql --with-mysqli --with-pdo-mysql \ -with-openssl --with-zlib --with-curl --with-gd \ -with-jpeg-dir --with-png-dir --with-freetype-dir \ -enalbe-mbstring --with-mcrypt --enable-hash && \ make -j 4 && make install && \ cp php.ini-production /usr/local/php/etc/php.ini && \ cp sapi/fpm/php-fpm.conf /usr/local/php/etc/php-fpm.conf && \ sed -i "90a \daemonize = no" /usr/local/php/etc/php-fpm.conf && \ mkdir /usr/local/php/log && \ cd / && rm -rf php* && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ENV PATH $PATH:/usr/local/php/sbin:/usr/local/php/bin COPY php.ini /usr/local/php/etc/ COPY php-fpm.conf /usr/local/php/etc/ WORKDIR /usr/local/php EXPOSE 9000 CMD ["php-fpm"] # docker build -t php:v1 -f Dockerfile-php .

Dockerfile-Tomcat

FROM centos:7 MAINTAINER xsbloc.com ENV VERSION=8.0.46 RUN yum install -y java-1.8-openjdk wget curl unzip iproute net-tools && \ yum clean all && \ rm -rf /var/cache/yum/* RUN wget http://192.168.31.211/apache-tomcat-${VERSION}.tar.gz && \ tar zxf apache-tomcat-${VERSION}.tar.gz && \ mv apache-tomcat-${VERSION} /usr/local/tomcat && \ rm -rf apache-tomcat-${VERSION}.tar.gz /usr/local/tomcat/webapps/* && \ mkdir /usr/local/tomcat/webapps/test & \ echo "ok" > /usr/local/tomcat/webapps/test/status.html && \ sed -i '1a JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"' /usr/local/tomcat/bin/catalina.sh && \ ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ENV PATH $PATH:/usr/local/tomcat/bin WORKDIR /usr/local/tomcat EXPOSE 8080 CMD ["catalina.sh", "run"]

快速部署LNMP网站平台并项目测试

  1. 自定义网络
docker network create lnmp
  1. 创建Mysql容器
docker run -d \ -name lnmp_mysql \ -net lnmp \ -mount src=mysql-vol,dst=var/lib/mysql \ e MYSQL_ROOT_PASSRORD=123456 -e MYSQL_DATABASE=wordpress mysql:5.7 --character-set-server=utf8
  1. 创建PHP容器
docker run -d --name lnmp_php --net lnmp --mount src=wwwroot,dst=/wwwroot php:v1
  1. 创建nginx容器
docker run -d --name lnmp_nginx --net lnmp -p 88:80 \ -mount type=bind,src=$(pwd)/nginx.conf,dst=/usr/local/nginx/conf/nginx.conf --mount src=wwwroot,dst=/wwwroot nginx:v1
  1. 以wordpress博客为例
https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tat.gz

企业级镜像创建Harbor

Harbor 概述
Harbor是由VMWare公司开源的容器镜像创建。事实上,Habor是在Docker Registry上进行了相应的企业级扩展,从而获得了更加广泛的应用,这些新的企业级特性包括:管理用户界面,基于角色的访问控制,AD/LADP集成以及审计日志等,足以满足基本企业需求。
官方地址:https://vmware.github.io/harbor/cn/

组件功能
harbor-adminiserver配置管理中心
harbor-dbMysql数据库
harbor-jobservice负载镜像复制
harbor-log记录操作日志
harbor-uiWeb管理页面和API
nginx前端代理,负责前端页面和镜像上传/下载转发
redis会话
registry镜像存储

Harbor部署

# github下载稳定版本,需要docker-compose编排工具 # tar zxvf harbor-offline-install-v1.5.1.tgz # cd harbor # vim harbor.cfg hostname = 192.168.1.120 # ip或域名 ui_url_protocol = http # 对外最好使用https harbor_admin_password = YOUR_PASSWORD # ./prepare # ./install.sh

Harbor基本使用

  1. 配置http镜像仓库可信任
# 非https需要添加可信任 # vim /etc/docker/daemon.json {"insecure-registries":["reg.xsbloc.com"]} # systemctl restart docker
  1. 打标签
docker tag centos:6 reg.xsbloc.com/jeff/centos:6
  1. 上传 docker push reg.xsbloc.com/jeff/centos:6

  2. 下载 docker pull reg.xsbloc.com/jeff/centos:6 —

图形化管理Portainer

portainer

portainer是一个开源、轻量级Docker管理用户界面,基于Docker API,可管理Docker主机或Swarm集群,支持最新版Docker和Swarm模式

  1. 创建卷
docker volume create portainer_data
  1. 创建portainer容器
docker run -d \ p 9000:9000 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data \ portainer/portainer

构建Docker容器监控系统

Prometheus

prometheus特点

  • 多维数据模型:由度量名称和键值对标识的时间序列数据
  • PromSQL:一种灵活的查询语言,可以利用多数据完成复杂的查询
  • 不依赖分布式存储,单个服务器节点可直接工作
  • 基于http的pull方式采集时间序列数据
  • 推送时间序列数据通过PushGateway组件支持
  • 通过服务发现或静态配置发现目标
  • 多种图形模式及仪表盘支持(grafana)

prometheus架构图

  • Prometheus Server: 收集指标和存储时间序列数据,并提供查询接口
  • ClientLibrary:客户端库
  • Push Gateway: 短期存储指标数据。主要用于临时性的任务
  • Exporters:采集已有的第三方服务监控指标并暴露metrics
  • Alertmanager:告警
  • Web UI:简单的Web控制台

实例:可以抓取的目标名称为实例(Instances) 作业:具有相同目标的实例集合称为作业(Job)

scrape_configs: job_name:'prometheus' static_configs: targets:['localhost:9090'] job_name:'node' static_configs: targets:['192.168.1.120:9090']

部署可以参考官方网站,直接使用docker进行部署

cAdvisor(Container Advisor)用于收集正在运行的容器资源使用和性能信息。

https://github.com/google/cadvisor # 项目地址直接使用容器运行

Grafana是一个开源的度量分析和可视见系统 (docker模板id:193)

本文由作者按照 CC BY 4.0 进行授权