# docker-training **Repository Path**: XuLin790/docker-training ## Basic Information - **Project Name**: docker-training - **Description**: Docker实训课程-Dockerfile - **Primary Language**: Docker - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 6763 - **Created**: 2018-01-03 - **Last Updated**: 2022-03-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #### docker上次分享回顾 查看docker是否安装:`yum search docker` 启动docker:`service docker start` 查找mysql镜像:`docker search mysql` 获取镜像: `docker pull docker.io/mysql:5.7.20` 列出本地镜像:`docker images` 运行镜像:`docker run -d -p 3306:3306 -name msyql -e MYSQL_ROOT_PASSWORD=123456 docker.io/mysql:5.7.20` 查看正在运行的镜像:`docker ps` 进入正在运行的镜像服务: `docker exec -it msyql bash` 文档 https://docs.docker.com/compose/ ##### 获取镜像 ###### docker pull ubuntu:12.04 ##### 列出本地镜像 ###### docker images ![image](http://wdb007.oss-cn-hangzhou.aliyuncs.com/docker/docker_images.png) ##### 创建镜像 ###### docker commit 或者 dockerFile #### 运行镜像 docker run -d -p 3306:3306 --name msyql -e MYSQL_ROOT_PASSWORD=123456 docker.io/mysql:5.7.20 ## 今日主要分享:Dockerfile介绍 ### 一、首先Docker是软件工业上的==集装箱==技术 ### 解决以下问题: - 在运输过程中,货物损坏 - 装卸、运输货物,效率低下 - 运输手续繁多及运输环节多 - 劳动强度大,及船舶周转慢 ### 集装箱特点: - 规则标准化,大大减少了包装费用 - 大大提升了货物装卸效率、及运输效率 - 不同种运输工具之间转换更容易 ### 所以,集装箱出现是传统行业中的一次重大变革 ### 同理,传统软件行业中存在的问题 - 软件更新发布低效 - 业务无法敏捷 - 环境一致性,难于保证 - 不同环境之间迁移成本太高 - 软件开发商,交付实施周期长---成本高 ### Docker就是容器--集装箱,有望或者说在很大程度上可以得到解决 ## 二、Docker的组成 #### Docker是一个C/S架构 - Docker Client: Docker的客户端 - Docker Server: Docker daemon的主要组成部分,接收用户通过Docker Client发送的请求,并按照相应的路由规则实现路由分发 - Docker ==Registry==: Registry是Docker镜像的中央存储仓库(pull/push) > 通过docker pull命令可以把Registry上的docker镜像,下载到服务器本地 > 通过docker push命令可以把服务器本地的docker镜像,上传到Registry上 > git仓库 **Registry在构建自动化平台,起着非常重要的作用!** _提示:Docker镜像运行之后会成为Docker容器----通过 docker run命令_ #### Docker容器启动速度非常快,体现在2个方面; 1.磁盘占用空间小,因为docker镜像采用了分层技术,构建的镜像大小,只有自身的大小,不包含父镜像的大小 2.内存消耗少,docker容器共享的宿主机的内核,没有操作的进程消耗 ## Docker实战准备 1. 首先登陆[OSChina Git](http://git.oschina.net) 2. 将[docker-training](https://gitee.com/XuLin790/docker-training)项目Fork到自己的仓库 3. 使用自己熟悉的SSH工具连接到服务器 4. 执行`git clone https://git.oschina.net/*YOURNAME*/docker-training.git`,将你的远程仓库clone到服务器 [Git 使用指南](http://git.oschina.net/progit/) 后续会构建4个docker镜像,分别为: > centos7 (基础镜像) > php-fpm mysql(中间件镜像) > worpdress(应用镜像) #### 什么是Dockerfile? > Dockerfile是自动构建docker镜像的配置文件,Dockerfile中的命令非常类似linux shell下的命令 > Dockerfile,可以让用户自定义构建docker镜像,支持以 # 开头的注释行 > 一般,Dockerfile分为4部分 - 基础镜像(父镜像)信息 - 维护者信息 - 镜像操作命令 - 容器启动命令 #### 为何把Dockerfile存放到git仓库中,并为每个项目创建git仓库? > 方便通过自动化平台,自动构建docker镜像 ## 三、Dockerfile介绍 ### 构建基础镜像wdb007/centos:7.1 ``` # # MAINTAINER Frank # DOCKER-VERSION 1.12.6 # # Dockerizing CentOS7: Dockerfile for building CentOS images # FROM centos:centos7.1.1503 MAINTAINER Frank ENV TZ "Asia/Shanghai" ENV TERM xterm ADD aliyun-mirror.repo /etc/yum.repos.d/CentOS-Base.repo ADD aliyun-epel.repo /etc/yum.repos.d/epel.repo RUN yum install -y curl wget tar bzip2 unzip vim-enhanced passwd sudo yum-utils hostname net-tools rsync man && \ yum install -y gcc gcc-c++ git make automake cmake patch logrotate python-devel libpng-devel libjpeg-devel && \ yum install -y --enablerepo=epel pwgen python-pip && \ yum clean all RUN pip install supervisor ADD supervisord.conf /etc/supervisord.conf RUN mkdir -p /etc/supervisor.conf.d && \ mkdir -p /var/log/supervisor EXPOSE 22 ENTRYPOINT ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"] ``` `FROM centos:centos7.1.1503` > 基于**父镜像**构建其他docker镜像,_父镜像_:可以通过docker pull 命令获得,也可以自己制作 `MAINTAINER Frank ` > Dockerfile维护者 `ENV TZ "Asia/Shanghai"` >ENV(environment)设置环境变量,一个Dockerfile中可以写多个。以上例子是:设置docker容器的时区为Shanghai ###### Dockerfile中有2条指令可以拷贝文件 `ADD aliyun-mirror.repo /etc/yum.repos.d/CentOS-Base.repo` > 拷贝本地文件到docker容器里,还可以拷贝URL链接地址下的文件,ADD还具有解压软件包的功能(支持gzip, bzip2 or xz) `COPY test /mydir` > 拷贝本地文件到docker容器 `RUN yum install -y curl wget....` > RUN命令,非常类似linux下的shell命令 `(the command is run in a shell - /bin/sh -c - shell form)` > 在Dockerfile中每执行一条指令(ENV、ADD、RUN等命令),都会生成一个docker image layer `RUN pip install supervisor` > supervisor进程管理系统,推荐使用 `ADD supervisord.conf /etc/supervisord.conf` > 添加supervisor的主配置文件,到docker容器里 `RUN mkdir -p /etc/supervisor.conf.d` > 创建存放启动其他服务"supervisor.conf"的目录,此目录下的所有以.conf结尾的文件,在启动docker容器的时候会被加载 `EXPOSE 22` > 端口映射 `EXPOSE :` > 推荐使用`docker run -p :` 来固化端口 `ENTRYPOINT ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"]` > 一个Dockerfile中只有最后一条`ENTRYPOINT`生效,并且每次启动docker容器,都会执行`ENTRYPOINT`,上面表示开启supervisord服务加载supervisord配置文件 ###### 以上文件就是用来生成第一个docker镜像的Dockerfile,通过`docker build`指令来生成docker镜像 `docker build -t [registry_url/namespace/wdb007/centos:7.1]` > 最完整的命名,7.1版本号写了就有版本号,不写默认latest `docker build -t wdb007/centos:7.1 .` > 如果Dockerfile在当前目录下,输入点`.`就可以进行加载当前目录下的`Dockerfile` > 如果不在当前目录下需要运行`docker build -t csphere/centos:7.1 `加载相对路径下的`Dockerfile` docker镜像的命名规则 `registry_url/namespace/image_name:tag` 默认`tag`是`latest` > 在构建Docker镜像时,如果有自己内部的yum源,替换成自己内部的yum源地址,可以加快构建速度。 > 如果第一次构建失败,会有部分镜像layer生成,第二次构建会基于第一次构建所生成的layer(use cache),继续构建 ``` Step 10 : EXPOSE 22 ---> Running in 0ed1c5479ebc ---> c57a5bac41c8 Removing intermediate container 0ed1c5479ebc Step 11 : ENTRYPOINT /usr/bin/supervisord -n -c /etc/supervisord.conf ---> Running in e16c7ac2fd45 ---> 185ef7b101a8 Removing intermediate container e16c7ac2fd45 Successfully built 185ef7b101a8 ``` 可以看到每执行一条`Dockerfile`的指令都会生成一个镜像的layer`c57a5bac41c8` `185ef7b101a8` 最后`185ef7b101a8`这个是docker镜像的ID,`185ef7b101a8`是由`c57a5bac41c8` `185ef7b101a8`...layers叠加而成,体现了docker镜像是分层的 ``` # docker images 查看当前主机本地有哪些docker镜像 REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE wdb007/centos 7.1 185ef7b101a8 40 minutes ago 451.9 MB ``` 通过docker镜像生成一个docker容器 `docker help run ` #查看`docker run`命令的使用方法 ##### 介绍日常工作中经常用到的参数: `docker run -it` #启动docker容器在前端 `docker run -d` #启动docker容器在后台 `docker run -p` `docker run -P` > 在Dockerfile中有一条指令是EXPOSE 22,如果使用`-P`,宿主机会随机选择一个`没有被使用的端口`和docker`容器的22端口`做`端口映射`,如果docker主机或者容器重启后,宿主机又会随机选择一个没有被使用的端口和docker容器的22端口做端口映射,这样端口会发生`变化` > 如果使用`-p`,比如`2222:22`,这样不管是docker主机或者容器重启后,2222:22端口都是这样来映射,`不会发生改变` 生成docker容器 `docker run -d -p 2222:22 --name base wdb007/centos:7.1` `3a0d83bcdc70517c72d28afb0aae231536c8491bda806adb35969b04c2fa5700` 参数说明: - -d 后台运行 - -it 前台交互式运行 - -P 22 将宿主机的一个未使用的随机端口映射到容器的22端口 - -p 2222:22 将宿主机的2222端口映射到容器的22端口 - --name base 给容器命名为base - wdb007/centos:7.1 使用这个镜像镜像创建docker容器 查看Docker容器 `docker ps ` > `ps`默认只会显示容器在“running”的状态的,容器列表 `docker ps -a` > `ps -a` 会查看到所有的容器列表 ``` CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3a0d83bcdc70 wdb007/centos:7.1 "/usr/bin/supervisord" 3 minutes ago Up 3 minutes 0.0.0.0:2222->22/tcp base 46b4919ae7f6 docker.io/mysql:5.7.20 "docker-entrypoint.sh" 5 days ago Up 5 days 0.0.0.0:3306->3306/tcp msyql ``` ### 中间件镜像 基础镜像 -- ==中间件镜像== -- 应用镜像 ``` # cd usr/docker-training/php-fpm/ # ls Dockerfile nginx_nginx.conf supervisor_nginx.conf nginx_default.conf php_www.conf supervisor_php-fpm.conf ``` 各文件解释: > nginx_nginx.conf 替换默认的nginx.conf文件 > nginx_default.conf 替换默认的default.conf文件 > php_www.conf 修改apache用户为nginx > supervisor_nginx.conf 添加启动nginx的supervisor文件 > supervisor_php-fpm.conf 添加启动php-fpm的supervisor文件 ``` # cat Dockerfile # # MAINTAINER Frank # DOCKER-VERSION 1.12.6 # # Dockerizing php-fpm: Dockerfile for building php-fpm images # FROM wdb007/centos:7.1 MAINTAINER Frank # Set environment variable ENV APP_DIR /app RUN yum -y install nginx php-cli php-mysql php-pear php-ldap php-mbstring php-soap php-dom php-gd php-xmlrpc php-fpm php-mcrypt && \ yum clean all ADD nginx_nginx.conf /etc/nginx/nginx.conf ADD nginx_default.conf /etc/nginx/conf.d/default.conf ADD php_www.conf /etc/php-fpm.d/www.conf RUN sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/' /etc/php.ini RUN mkdir -p /app && echo "" > ${APP_DIR}/info.php EXPOSE 80 443 ADD supervisor_nginx.conf /etc/supervisor.conf.d/nginx.conf ADD supervisor_php-fpm.conf /etc/supervisor.conf.d/php-fpm.conf ONBUILD ADD . /app ONBUILD RUN chown -R nginx:nginx /app ``` 命令解析: `ONBUILD ADD . /app` `ONBUILD` 在生成当前docker镜像的时候不生效,在子镜像生效;`ONBUILD`在产品发布时起着非常重要的作用!举例 > A镜像中有`ONBUILD`指令,在构建A镜像时`ONBUILD`指令不执行;B镜像`FROM A`,在构建B镜像时`ONBUILD`指令开始执行; 如何给docker镜像命名: - registry-url: registry服务器的域名或者ip - namespace: - image-name: docker镜像的名字 - tag: docker镜像的版本号,推荐使用应用服务的版本号来命名,如`php-fpm:5.4` 生成php-fpm镜像 `docker build -t wdb007/php-fpm:5.4 .` ``` Step 12 : ONBUILD add . /app ---> Running in 9e21ede67350 ---> 7541483a5a76 Removing intermediate container 9e21ede67350 Step 13 : ONBUILD run chown -R nginx:nginx /app ---> Running in ab55fc7a46a1 ---> c61699e8c237 Removing intermediate container ab55fc7a46a1 Successfully built c61699e8c237 ``` 生成website容器: `docker run -d -p 9380:80 --name website wdb007/php-fpm:5.4` `4d3b24d7486327483dfd2977149fd67cbe9860519963f36fd9217177421e802f` 参数解释: - -d 后台运行 - -p 8080:80 将宿主机的8080端口映射到容器的80端口 - --name website 给容器命名为website - wdb007/php-fpm:5.4 使用这个镜像镜像创建docker容器 使用浏览器访问:`http://your_ip:9380/info.php` 测试环境 `http://47.96.11.14:9380/info.php` 进入一个正在运行的docker容器 `docker exec -it website /bin/bash` ``` # supervisorctl 查看当前容器中使用supervisor启动了哪些服务 nginx RUNNING pid 9, uptime 0:04:31 php-fpm RUNNING pid 10, uptime 0:04:31 ``` ##wdb007/mysql:5.5 ``` cat Dockerfile # # MAINTAINER Frank # DOCKER-VERSION 1.12.6 # # Dockerizing Mariadb: Dockerfile for building Mariadb images # FROM wdb007/centos:7.1 MAINTAINER Frank ENV DATA_DIR /var/lib/mysql # Install Mariadb RUN yum install -y mariadb mariadb-server && \ yum clean all ADD mysqld_charset.cnf /etc/my.cnf.d/ COPY scripts /scripts RUN chmod +x /scripts/start EXPOSE 3306 VOLUME ["/var/lib/mysql"] ENTRYPOINT ["/scripts/start"] ``` 命令解析: `VOLUME ["/var/lib/mysql"]` > `VOLUME`指令,宿主机文件目录和docker容器文件目录做映射 `ENTRYPOINT ["/scripts/start"]` >`ENTRYPOINT`在每次启动docker容器时都会被执行,此例,是运行了一个shell脚本"/scripts/start" 每次启动都会运行`/scripts/start`脚本,脚本内容如下: ``` # cat start #!/bin/bash set -e # # When Startup Container script # if [[ -e /scripts/firstrun ]]; then # config mariadb /scripts/firstrun_maria rm /scripts/firstrun else # Cleanup previous mariadb sockets if [[ -e ${DATA_DIR}/mysql.sock ]]; then rm -f ${DATA_DIR}/mysql.sock fi fi exec /usr/bin/mysqld_safe ``` 脚本解析: - `set -e` 脚本中只要有一行有错误,就会中断脚本执行 - 如果firstrun文件存在,执行firstrun_maria脚本,如果不存在,删除mysql.sock文件,并启动Mariadb > firstrun_maira脚本是初始化Mariadb,以及设置数据库用户和密码,详情内容请自行阅读[脚本文件](http://git.oschina.net/dockerf/docker-training/blob/master/mysql/scripts/firstrun_maria?dir=0&filepath=mysql%2Fscripts%2Ffirstrun_maria&oid=788bfb61d8cc45a33b60cde5a0e98899ee08f808&sha=3a86a4767292c267af0794628efb76fe31e754e6) 构建mysql docker镜像 生产数据库mysql 5.7.19 `docker build -t wdb007/mysql:5.7.19 .` ###docker volume 保证删除容器后,数据不被删除 - 保存容器中的数据 - 数据共享 使用方法: 1.在Dockerfile中定义VOLUME["/data"] 2.通过`docker run -d -v :` ###案例: 1. 创建mysql容器,不挂载docker volume,删除后,数据是否存在 2. 创建mysql容器,挂载docker volume,删除后,数据是否存在 运行不挂载docker volume的mysql容器 `# docker run -d -p 9306:3306 --name dbserver wdb007/mysql:5.7.19` `bfdfed5f9afab832df16fc112488ae51ae9e8d0200d3e2544931e277b17afb79` 删除docker容器,容器里面的数据都会随着容器被删除而删除 ``` # docker rm dbserver Error response from daemon: You cannot remove a running container bfdfed5f9afab832df16fc112488ae51ae9e8d0200d3e2544931e277b17afb79. Stop the container before attempting removal or use -f ``` 参数解释: - `docker rm` 删除状态为“Exited”的docker容器 - `docker rm -f` 强制删除docker容器 运行挂载docker volume的mysql容器 主机目录:容器目录 `docker run -d -p 9306:3306 -v /var/lib/docker/vfs/dir/mydata:/var/lib/mysql wdb007/mysql:5.7.19` `8952dfb07370e90b83b9e84cf2d46f37f00f362dbe8d867fcb445b0c1d88e53b` `docker exec -it f49 /bin/bash` 登陆数据库创建mydb数据库 ``` # mysql # show databases; # create database mydb; Query OK, 1 row affected (0.00 sec) # show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mydb | | mysql | | performance_schema | | test | +--------------------+ 5 rows in set (0.00 sec) # exit exit ``` 查看主机文件目录下,是否已生成mydb数据库目录文件 ``` # ls /var/lib/docker/vfs/dir/mydata/ aria_log.00000001 aria_log_control ibdata1 ib_logfile0 ib_logfile1 mydb mysql mysql.sock performance_schema test ``` ``` 停止docker容器 # docker stop 8952d 8952d 删除docker容器,查看`mydb`目录是否被删除 # docker rm 8952d 8952d # ls /var/lib/docker/vfs/dir/mydata/ 验证,挂载docker volume后,容器被删除掉,数据还在 aria_log.00000001 ibdata1 ib_logfile1 mysql performance_schema aria_log_control ib_logfile0 mydb mysql.sock test ``` 新创建一个容器,挂载到刚才的数据目录下,是否可以把之前的数据库加载回来 `docker run -d -p 9306:3306 --name newdb -v /var/lib/docker/vfs/dir/mydata:/var/lib/mysql wdb007/mysql:5.7.19` `4ae3cc88c93b2c6fcd85f161397c2e7d8b907d1d52e1713549c4934017ed3754` `docker exec -it newdb /bin/bash` ``` # mysql MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mydb | | mysql | | performance_schema | | test | +--------------------+ 5 rows in set (0.00 sec) ``` 验证结果: 只要保证数据在,重新创建一个容器挂载回之前的数据目录,业务即可恢复(容器可随意删除、创建) ## 应用镜像 ## wdb007/wordpress:4.2 ``` # cd /usr/docker_train/docker-training/wordpress/ # ls -a . license.txt wp-config-sample.php wp-login.php .. readme.html wp-content wp-mail.php Dockerfile wp-activate.php wp-cron.php wp-settings.php .dockerignore wp-admin wp-includes wp-signup.php index.php wp-blog-header.php wp-links-opml.php wp-trackback.php init.sh wp-comments-post.php wp-load.php xmlrpc.php /usr/docker_train/docker-training/wordpress # cat Dockerfile from wdb007/php-fpm:5.4 add init.sh /init.sh entrypoint ["/init.sh", "/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"] ``` 使用docker后,在项目代码目录下,写Dockerfile文件,非常方便把项目代码直接打包到docker镜像中,如有哪些文件不想被打包进去,可以在`.dockerignore`文件中定义 Dockerfile解析: - wordpress镜像是基于wdb007/php-fpm:5.4来进行构建 - `ONBUILD`指令生效,把代码文件拷贝到网站根目录下 - `init.sh`脚本对WordPress连接mysql数据库进行配置,固运行wordpress镜像后,只需要进行配置WordPress即可,数据库已准备就绪! 生成WordPress镜像 `docker build -t wdb007/wordpress:4.2 .` 查看当前主机本地都有哪些docker镜像 `docker images` 创建WordPress准备 查看主机ip地址 `ifconfig eth0` 172.16.23.197 创建WordPress容器: ``` docker run -d -p 9308:80 --name wordpress -e WORDPRESS_DB_HOST=172.16.23.197 -e WORDPRESS_DB_USER=admin -e WORDPRESS_DB_PASSWORD=123456 -e MYSQL_PORT_3306_TCP=9306 wdb007/wordpress:4.2 7a78c3cd7bd6e333d644c2d33410446b19f11e0682bcd401190b43f5c5b7a842 ``` 参数解析: - -d 后台运行 - -p 9381:80 将宿主机的9381端口映射到容器的80端口 - --name wordpress 给容器命名为wordpress - -e WORDPRESS_DB_HOST=172.16.23.197 数据库主机的ip地址(或者域名) - -e WORDPRESS_DB_USER=admin 数据库的用户,默认是admin - -e WORDPRESS_DB_PASSWORD=123456 登陆数据的密码,默认是123456 - wdb007/wordpress:4.2使用此镜像创建WordPress容器 访问`http://your_ip`,选择语言,并进行设置`wordpress` ## ENTRYPOINT和CMD的区别 ENTRYPOINT解析 定义: An ENTRYPOINT allows you to configure a container that will run as an executable 运行一个Docker容器像运行一个程序一样 ENTRYPOINT的使用方法: 1.ENTRYPOINT ["executable", "param1", "param2"] (the preferred exec form) > 推荐使用1方法,启动起来后,pid为1 2.ENTRYPOINT command param1 param2 (shell form)  >启动起来后,pid号为shell命令执行完的pid号 CMD解析 CMD的使用方法: 1.CMD ["executable","param1","param2"] (exec form, this is the preferred form) >运行一个可执行的文件并提供参数 2.CMD ["param1","param2"] (as default parameters to ENTRYPOINT)  >为ENTRYPOINT指定参数 3.CMD command param1 param2 (shell form)  >是以”/bin/sh -c”的方法执行的命令 实战测试`CMD` ``` vim Dockerfile FROM centos:centos7.1.1503 CMD ["/bin/echo", "This is test cmd"] ``` 生成cmd镜像 `docker build -t wdb007/cmd:0.1 .` 生成cmd容器,进行测试 `docker run -it --rm wdb007/cmd:0.1` `This is test cmd` 测试是否可以替换`cmd`的命令 ``` docker run -it wdb007/cmd:0.1 /bin/bash [root@c1963a366319 /]# ``` 测试结果,在Dockerfile中定义的`CMD`命令,在执行`docker run`的时候,`CMD`命令可以被替换。 实战测试`ENTRYPOINT` ``` FROM centos:centos7.1.1503 ENTRYPOINT ["/bin/echo", "This is test entrypoint"] ``` 生成ent(entrypoint)镜像 `docker build -t wdb007/ent:0.1 .` 生成ent容器,进行测试 ``` docker run -it wdb007/ent:0.1 This is test entrypoint ``` 测试是否可以替换`entrypoint`的命令 ``` docker run -it wdb007/ent:0.1 /bin/bash This is test entrypoint /bin/bash ``` 测试结果,在Dockerfile定义的`ENTRYPOINT`命令,通过以上方式不能被替换 实战再次测试`ENTRYPOINT` `docker run -it --entrypoint=/bin/bash wdb007/ent:0.1` 测试结果,ENTRYPOINT命令也可以被替换,需要在执行`docker run`时添加`--entrypoint=`参数,此方法多用来进行调试