Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
官网
构建三步骤
1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2:指令按照从上到下,顺序执行
3:#表示注释
4:每条指令都会创建一个新的镜像层并对镜像进行提交
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
1 Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
2 Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
3 Docker容器,容器是直接提供服务的。
FROM 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
**MAINTAINER ** 这条命令主要是指定维护者信息,方便他人寻找作者 指令后面的内容其实没有规定写什么, 只要可以联系上作者即可,一般使用邮箱地址 格式为 MAINTAINER Name 。注意:这个标签已经弃用,但现在还有很多 Dockerfi 使用这个标签,所以短时间内不会删除 现在推荐使用更灵活的 LABEL 命令,详见 面的讲解。
EXPOSE 当前容器对外暴露出的端口
WORKDIR 指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
USER 指定该镜像以什么样的用户去执行,如果都不指定,默认是root
ENV 用来在构建镜像过程中设置环境变量
ENV MY_PATH /usr/mytest
这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;
也可以在其它指令中直接使用这些环境变量,
比如:WORKDIR $MY_PATH
ADD 将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
VOLUME 容器数据卷,用于数据保存和持久化工作
shell格式: RUN yum -y install vim
到 shell 格式中,可以使用反斜杠将单个 RUN 命令跨到下一行
RUN echo ” Hello ”&& \
echo "World”\
&& echo ” Docker”
exec格式:RUN [“可执行文件”,“参数1”,“参数2”]
例:RUN [“./test.php”,“dev”,“offline”] 等价于 ./test.php dev offline
以这种格式运行程序,可以免除运行 n/sh 的消耗 这种格式是用 Ison 格式将程序名 与所需参 数组成一个字符串数组,所以如果参数中有引号等特殊字符,贝lj 需要进行转义
RUN是在 docker build时运行
CMD是在docker run时运行
CMD指令可以有多条,但只有最后一个生效,CMD会被docker run后面的参数替换
上面这个实例什么意思呢,官网编写的关于tomcat的Dockerfile文件的最后一行是运行catalina.sh脚本
能访问tomcat
加上/bin/bash
则不能访问tomcat
FROM ubuntu
CMD [” echo ” , ” Hello Ubuntu” ]
docker build -t user/test .
docker run -it imageId echo "Hello Docker"这个方式启动容器时,echo "HelloDocker”命令会覆盖原有的CMD命令。也就是说,CMD 命令可以通过docker run命令覆盖,这一点也是CMD和ENTRYPOINT指令的最大区别。
也是用来指定一个容器启动时要运行的命令
类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
FROM ubuntu
ENTRYPOINT [ ” echo” ]
(1)基础镜像:centos:centos7.5.1804;
(2)作者:Chinaskill;
(3)修改配置文件中的bind 127.0.0.1为bind 0.0.0.0;
(4)设置Redis免密,并关闭保护模式;
(5)开放端口:6379;
(6)设置服务开机自启。
[root@master redis]# cat Dockerfile
FROM centos:centos7.5.1804
MAINTAINER Chinaskill
RUN rm -rf /etc/yum.repos.d/*
ADD ftp.repo /etc/yum.repos.d/ftp.repo
RUN yum clean all
RUN yum list
RUN yum install -y redis
RUN sed -i 's/bind 127.0.0.1/bind 0.0.0.0/g' /etc/redis.conf
RUN sed -i 's/protected-mode yes/protected-mode no/g' /etc/redis.conf
RUN sed -i 's/daemonize no/daemonize yes/g' /etc/redis.conf
EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server","/etc/redis.conf"]
(1)基础镜像:centos:centos7.5.1804;
(2)作者:Chinaskill;
(3)设置数据库密码:123456;
(4)创建数据库gpmall并导入数据库文件gpmall.sql;
(5)设置字符编码:UTF-8;
(6)开放端口:3306;
(7)设置服务开机自启。
[root@master redis]# cd /root/mariadb/
[root@master mariadb]# ls
Dockerfile ftp.repo gpmall.sql init.sh
[root@master mariadb]# cat Dockerfile
FROM centos:centos7.5.1804
MAINTAINER Chinaskill
RUN rm -rf /etc/yum.repos.d/*
ADD ftp.repo /etc/yum.repos.d/
RUN yum install -y mariadb-server
ADD init.sh /root/init.sh
RUN chmod +x /root/init.sh
ADD gpmall.sql /root/gpmall.sql
RUN /root/init.sh
ENV C.LANG UTF-8
EXPOSE 3306
CMD ["mysqld_safe"]
(1)基础镜像:centos:centos7.5.1804;
(2)作者:Chinaskill;
(3)开放端口:2181;
(4)设置服务开机自启。
[root@master zookeeper]# ls
Dockerfile ftp.repo zookeeper-3.4.14.tar.gz
[root@master zookeeper]# cat Dockerfile
FROM centos:centos7.5.1804
MAINTAINER Chinaskill
RUN rm -rvf /etc/yum.repos.d/*
COPY ftp.repo /etc/yum.repos.d/local.repo
RUN yum -y install java-1.8.0
ADD zookeeper-3.4.14.tar.gz /usr/local
ENV ZOOKEEPER_HOME /usr/local/zookeeper-3.4.14
ENV PATH $PATH:$JAVA_HOME/bin:$JRE_HOME/bin:$ZOOKEEPER_HOME/bin
RUN cp $ZOOKEEPER_HOME/conf/zoo_sample.cfg $ZOOKEEPER_HOME/conf/zoo.cfg
EXPOSE 2181
CMD $ZOOKEEPER_HOME/bin/zkServer.sh start-foreground
仓库名、标签都是的镜像,俗称dangling image
虚悬镜像的由来
通常出现这种情况,是因为构建了一个新镜像,然后为该镜像打了一个已经存在的标签。接着Docker会移除旧镜像上面的标签,将该标签标在新的镜像之上。例如,首先基于alpine:3.4构建一个新的镜像,并打上dodge:challenger
标签。然后更新Dockerfile
,将alpine:3.4
替换为alpine:3.5
,并且再次执行docker image build
命令。该命令会构建一个新的镜像,并且标签为dodge:challenger
,同时移除了旧镜像上面对应的标签,旧镜像就变成了悬虚镜像
查询显示虚悬镜像
docker images -f dangling=true
删除虚悬镜像
docker rmi $(docker images -q -f dangling=true)
1.修改之前的SpringBoot项目yml中数据库配置,改为容器化的mysql地址
2.根据实体类新建数据库
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id int(20) NOT NULL COMMENT '主键ID' auto_increment,
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Banana', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Milk', 21, '[email protected]'),
(6,'zs@qq',10,'asd'),
(5, 'Apple', 24, '[email protected]');
3.项目打包
4. 容器化myqsl
docker run -d -p 3306:3306 --privileged=true -v /pyy/mysql/log:/var/log/mysql -v /pyy/mysql/data:/var/lib/mysql -v /pyy/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=a --name mysql mysql:5.7
5. 构建镜像
[root@VM-16-8-centos springboot_test]# cat Dockerfile
FROM java:8
MAINTAINER pyy
VOLUME /tmp
ADD sys-admin-0.0.1-SNAPSHOT.jar pyy_docker.jar
RUN bash -c ‘touch /pyy_docker.jar’
ENTRYPOINT [“java”,“-jar”,“/pyy_docker.jar”]
EXPOSE 8080
docker build -t pyy_docker:1.0 .
6.运行容器
docker run -d -p 8080:8080 pyy_docker:1.6
7.测试
docker不启动,默认网络情况
docker启动后,网络情况
[root@VM-16-8-centos springboot_test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2c74a4b5d76a bridge bridge local
dd3008378058 host host local
9ebd6b25e4c3 none null local
常用命令
查看网络
docker network ls
查看网络源数据
docker network inspect XXX网络名字
删除网络
docker network rm XXX网络名字
案例
[root@VM-16-8-centos springboot_test]# docker network create test_docker_network
7a7c98e51c6effc0498579ec3cf9bfe6b0a9052ae8c3996781f61389b2529165
[root@VM-16-8-centos springboot_test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2c74a4b5d76a bridge bridge local
dd3008378058 host host local
9ebd6b25e4c3 none null local
7a7c98e51c6e test_docker_network bridge local
[root@VM-16-8-centos springboot_test]# docker network rm test_docker_network
test_docker_network
[root@VM-16-8-centos springboot_test]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2c74a4b5d76a bridge bridge local
dd3008378058 host host local
9ebd6b25e4c3 none null local
网络模式能干嘛
容器间的互联和通信以及端口映射
容器IP变动时候可以通过服务名直接网络通信而不受到影响
小总结
容器实例内默认网络IP生产规则
运行centos1和centos2,查看它们的ip分别为172.16.0.2,172.16.0.3。那么当centos2挂掉的话,在新建容器centos3,那么它的ip就会变为172.16.0.3
很像交换机
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,==它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。==Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
1 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
2 docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge=,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
3 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
3.1 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
3.2 每个容器实例内部也有一块网卡,每个接口叫eth0;
3.3 docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
错误的写法:
docker run -d -p 8083:8080 --network host --name tomcat83 pyy/tomcat8-jdk8
正确的写法
docker run -d --network host --name tomcat83 pyy/tomcat8-jdk8
http://宿主机IP:8080/
在CentOS里面用默认的火狐浏览器访问容器内的tomcat83看到访问成功,因为此时容器的IP借用主机的,
所以容器共享宿主机网络IP,这样的好处是外部主机与容器可以直接通信。
禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
在none模式下,并不为Docker容器进行任何网络配置。
也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo
需要我们自己为Docker容器添加网卡、配置IP等。
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的.
docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
能干嘛
docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具
例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。。。。。。
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
安装
[root@VM-16-8-centos springboot_test]# curl -L "https://github.com/docker/compose/releases/download/1.29.2
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 664 100 664 0 0 982 0 --:--:-- --:--:-- --:--:-- 982
100 12.1M 100 12.1M 0 0 29870 0 0:07:06 0:07:06 --:--:-- 64748
[root@VM-16-8-centos springboot_test]# chmod +x /usr/local/bin/docker-compose
[root@VM-16-8-centos springboot_test]# cd /usr/local/bin/
[root@VM-16-8-centos bin]# vim docker-compose
[root@VM-16-8-centos bin]# ll
total 13420
-rwxr-xr-x 1 root root 1001112 Aug 5 2020 busybox-x86_64
-rwxr-xr-x 1 root root 12737304 Apr 6 10:17 docker-compose
[root@VM-16-8-centos bin]# docker-compose --version
docker-compose version 1.29.2, build 5becea4c
一文件
docker-compose.yml
两要素
服务(service)
一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
工程(project)
由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
Compose使用的三个步骤
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
跟着官网写个wordpress来写个实例
创建目录my_wordpress
进入目录,创建docker-compose.yml文件
version: "3.9"
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
volumes:
- wordpress_data:/var/www/html
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
wordpress_data: {}
docker-compose up -d
项目目录运行。
[root@VM-16-8-centos my_wordpress]# docker-compose up -d
Creating network "my_wordpress_default" with the default driver
Creating volume "my_wordpress_db_data" with default driver
Creating volume "my_wordpress_wordpress_data" with default driver
Pulling wordpress (wordpress:latest)...
latest: Pulling from library/wordpress
c229119241af: Already exists
47e86af584f1: Pull complete
e1bd55b3ae5f: Downloading [====> ] 7.903MB/91.6MB
e1bd55b3ae5f: Pull complete
1f3a70af964a: Pull complete
0f5086159710: Pull complete
7d9c764dc190: Pull complete
ec2bb7a6eead: Pull complete
9d9132470f34: Pull complete
fb23ab197126: Pull complete
cbdd566be443: Pull complete
be224cc1ae0f: Pull complete
629912c3cae4: Pull complete
f1bae9b2bf5b: Pull complete
19542807523e: Pull complete
59191c568fb8: Pull complete
30be9b012597: Pull complete
bb41528d36dd: Pull complete
bfd3efbb7409: Pull complete
7f19a53dfc12: Pull complete
23dc552fade0: Pull complete
5133d8c158a7: Pull complete
Digest: sha256:c8d7b938e831b715cf16f22b678f9c7a0ffd5e5efa9b9b2d77f39bed5cf5b2fd
Status: Downloaded newer image for wordpress:latest
Creating my_wordpress_db_1 ... done
Creating my_wordpress_wordpress_1 ... done
测试
在云服务器上部署的记得放开开云服务器的端口
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
官网
因为我docker环境部署在了云服务器上,所以直接选本地即可
测试
docker stats
docker ps
docker stats
用来查看容器占用资源
通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,一般小公司够用了。。。。
但是,
docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能
CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
下面我们用docker-compose一键部署三剑客
version: '3.1'
volumes:
grafana_data: {}
services:
influxdb:
image: tutum/influxdb:0.9
restart: always
environment:
- PRE_CREATE_DB=cadvisor
ports:
- "8083:8083"
- "8086:8086"
volumes:
- ./data/influxdb:/data
cadvisor:
image: google/cadvisor
links:
- influxdb:influxsrv
command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
restart: always
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
grafana:
user: "104"
image: grafana/grafana
user: "104"
restart: always
links:
- influxdb:influxsrv
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- HTTP_USER=admin
- HTTP_PASS=admin
- INFLUXDB_HOST=influxsrv
- INFLUXDB_PORT=8086
- INFLUXDB_NAME=cadvisor
- INFLUXDB_USER=root
- INFLUXDB_PASS=root