以前一直使用 Vagrant 作为自己的开发环境,并且在上家公司也推行大家采用 Vagrant 作为开发环境,保障公司使用的是同一套开发环境。随着docker的流行,越来越多的人在docker上运行自己的项目,利用docker也非常方便模拟各种线上集群,相比虚拟机效率会更高,不管是搭建还是运行。
网络上关于docker搭建环境的资料非常之多了,但自己一直没有进行过实践。纸上得来终觉浅,只有自己动过手之后,才能对相关的概念更熟悉。花了将近2天时间折腾,终于算是把docker的开发环境搭建好了,对他的很多概念也又了更深入的认识。整理一下整个过程,方便以后查漏补缺。
下面就来开启docker之旅吧,打算利用docker完成以下任务:
涉及的命令介绍
这仅仅是操作笔记,不涉及 Docker 原理什么之类的知识,重点是如何应用。为了后续理解方便,先把用到的相关命令在这里进行整体介绍。
查找镜像
➜ ~/home/dockerenv >docker search mysql
上面这个命令就是查找 mysql 镜像。对应的可以将 mysql 替换成其它想要查找的镜像名称。该命令常用选项是:-s
。可以设置搜索条件:多少个start以上的镜像。
➜ ~/home/dockerenv >docker search -s 100 mysql
搜索有100个以上start的 mysql 镜像。
获取镜像
docker pull centos7
这个命令会把镜像克隆到本地,就像:git clone
一样的效果。关于什么是镜像、容器之类的概念不在我的讲解范畴了。
查看与删除镜像
➜ ~/home/dockerenv >docker image ls
会列出当前所有的本地安装了的镜像。看到了有哪些镜像,有时候一个镜像我们用不到了,想把它干掉,为硬盘腾腾位置,可以用下面的命令:
➜ ~/home/dockerenv >docker rmi 0d16d0a97dd1 # 编号是 image id
创建镜像 - Dockerfile
docker的镜像可以从官方直接拉取,也可也通过 Dockerfile 进行定制,写好 Dockerfile 文件后,可以执行下面的命令运行镜像。
➜ ~/home/dockerenv >docker build -t nginx:1.14.0 .
这里的结尾有个 .
它表示上下文,而不是说 Dockerfile 的路径。举例来说,在 Dockerfile 中常常用 Copy 指令,它拷贝的文件必须要在这个上下文中。
Dockerfile的主要作用是:自己根据基础镜像,重新定制镜像,而不是直接从官方仓库拿现成的使用。
具体含义可以看这里:
https://yeasy.gitbooks.io/docker_practice/content/image/build.html
启动容器
➜ ~/home/dockerenv >docker run -it --rm php:7 bash
上面的命令会启动一个容器,并且分配一个伪终端,退出后容器就会被删除。
➜ ~/home/dockerenv >docker run -d -p 9000:9000 php:7
这个命令会在后台运行一个容器,此容器不会因为退出就被删除,可以重复进行start、stop操作。
上面两种容器启动的操作方式,在我的文章中其实不会出现,我的环境是基于docker-compose + Dockerfile 来搭建的。因为根据最佳实践:一个容器内部只包含一个进程,像上面我需要安装:PHP/Golang/Redis/Nginx/Mysql等,就算不算主从也需要启动5个容器,每次这样启动都要累死,还不说需要管理容器之间的互联。因此我使用Compose来定义和运行多个 Docker 容器的应用。
查看容器信息
➜ ~/home/dockerenv >docker inspect a49dfb2e6f45 # image id
通过该命令可以看到容器的完整信息,我用这个命令主要是在进行容器互联的时候,检查容器的网络与IP相关的情况。
进入容器
➜ ~/home/dockerenv >docker exec -it e8d740a6ac7a bash # image id
上面的命令可以进入容器,让你感觉像是 ssh 到了远程机器一样的感觉。
停止、启动
➜ ~/home/dockerenv >docker stop a49dfb2e6f45 # image id
如果容器是在后台启动,可以通过该方式停止容器。停止后可以使用下面的命令启动容器:
➜ ~/home/dockerenv >docker start a49dfb2e6f45 # image id
查看与删除容器
容器也可以像镜像一样进行查看
➜ ~/home/dockerenv >docker ps
上面的命令只会显示启动了的镜像,如果要查看所有镜像,可以添加 -a
选项。
如果某个容器不需要了,可以使用下面的命令进行删除:
➜ ~/home/dockerenv >docker rm 0d848bc87fe7 # image id
容器的删除并不会影响镜像,镜像可以继续用来启动新的容器。并且如果依赖某个镜像创建的容器没有被删除,该镜像是不能直接删除的,需要先删除容器后才能继续删除镜像。
Compose 中的启动与停止
针对docker compose启动与停止用到下面的命令,个人感觉这就是批量操作,毕竟容器太多,一个一个操作太麻烦,容易遗漏等等问题。
批量启动:
➜ ~/home/dockerenv >docker-compose up -d
虽然该命令并不是单纯的启动容器,它非常强大,将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。
如果已经创建完了,也可以用下面的命令来启动已经创建的容器。
➜ ~/home/dockerenv >docker-compose start
如果想要停止容器可以使用下面的命令:
➜ ~/home/dockerenv >docker-compose stop
当然这些命令的运行,要在 docker-compose.yml
文件所在的目录下运行,否则它也不知道该启动或关闭哪些容器。
基本用到的命令大概就是上面这些,接下来先说说 docker-compose.yml
文件的编写。
Docker Compose构建环境
Docker Compose 可以把多个容器方便的管理起来,也就是所谓的编排技术。
编排技术的核心是 docker-compose.yml
这个模版文件。它定义了容器集群里每一个容器的镜像、数据卷挂载路径、端口、网络等。
以接下来要构建的环境来说明下,下面我将要搭建一个php7的开发环境,需要Nginx/PHP-FPM/MySQL/Redis进行配合。那么需要启动4个容器。对应的也需要4个镜像。整个环境的目录结构如下:
├── README.md
├── docker-compose.yml
├── logs
│ └── nginx
├── mysql
│ ├── conf
│ └── data
├── nginx
│ ├── Dockerfile
│ ├── conf
│ └── src
├── php7
│ ├── Dockerfile
│ ├── docker-compose.yml
│ ├── etc
│ ├── extensions
│ └── src
├── redis
│ ├── Dockerfile
│ ├── conf
│ ├── data
│ └── src
├── start.sh
├── stop.sh
└── www
└── abc
我的MySQL是直接使用的官方提供的镜像资源,而Redis/Nginx/PHP为了做定制化,我采用Dockerfile进行自定义。接下来按照每一个独立的服务分别进行一下说明。
MySQL服务
dev.mysql.srv:
image: mysql:5.7.22
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d
ports:
- "3307:3306"
restart: always
environment:
MYSQL_ROOT_PASSWORD: 123123
networks:
- default
image:是制定依赖的镜像,这里是Docker提供的镜像资源;
volumes:数据卷所挂载路径设置,主要是MySQL的数据保存的路径设置与配置文件的设置。它的主要作用是持久化数据,避免容器销毁后内部数据丢失;
ports:暴露到宿主机的端口。这个没什么太多说的,就是为了可以在宿主机访问到容器内部的服务;
restart:该命令是设置容器如果在某种情况下(非认为)退出了,容器重启的策略;
environment:设置镜像的环境变量,你可以进入镜像通过:echo $MYSQL_ROOT_PASSWORD
查看其值;
networks:设置网络,让所有的容器在一个网络中,方便容器互联互通。
这里还有一个点需要注意,dev.mysql.srv
,是我为mysql服务取的名字。取一个好的名字,非常便于后续容器互联的使用,比如这个名字,如果php代码需要填写mysql的host。我则可以直接使用它。
其它服务
剩下的三种服务配置方式基本上大同小异。我放在一起说明。
dev.nginx.srv:
image: lei_nginx:1.14.0
build: ./nginx
volumes:
- ./nginx/conf:/home/work/app/nginx/conf
- ./www:/home/work/www
ports:
- "80:8080"
- "443:443"
restart: always
networks:
- default
depends_on:
- dev.php-fpm.srv
dev.redis.srv:
image: lei_redis:3.2.11
build: ./redis
volumes:
- ./redis/conf:/home/work/app/redis/conf
- ./redis/data:/home/work/app/redis/data
ports:
- "6379:6379"
restart: always
networks:
- default
dev.php-fpm.srv:
image: lei_php:7.2.6
build: ./php7
volumes:
- ./php7/etc:/home/work/app/php/etc
- ./www:/home/work/www
ports:
- "9000:9000"
restart: always
networks:
- default
这里与MySQL最大的一个区别是多了一个 build 选项。这就是上面说到的这三个镜像都是我用Dockerfile定制的有关。你可以在对应的 build 指定的目录下看到 Dockerfile
这个文件。
另外一个需要注意的地方是Nginx中配置的 depends_on
选项,他的作用是指定依赖,因为Nginx中我配置了php-fpm。所以它启动前要确保php-fpm已经启动后,他才能正常的启动。
启动
为了减少太多概念的东西,你可以先直接从github拉取这部分配置,然后运行
➜ ~/home/dockerenv >./start.sh
Starting dockerenv_dev.php-fpm.srv_1 ... done
Starting dockerenv_dev.redis.srv_1 ... done
Starting dockerenv_dev.mysql.srv_1 ... done
Creating dockerenv_dev.nginx.srv_1 ... done
如果你是第一次运行 start.sh
,他还会去docker hub上拉取镜像,以及根据Dockerfile来定制镜像。所以会有非常多的输出信息。
然后访问:http://localhost 。应该就能够看到 phpinfo() 输出的信息。
总结
经过自己的熟悉,对基本的docker命令,以及docker的三个基础概念:仓库、镜像、容器有了充分的认识。利用 docker compose 搭建一个环境后,对于容器的互联也有了更深刻的体会,并且经过这种一个容器运行一个进程的方式,对系统也有了一些更深的认识。在利用Dockerfile定制镜像的过程中,通过反复的 build 镜像,对理解容器的分层、如何确保镜像体积更小方面有了相当多的实践,特别是在ENTRYPOINT的设置上,认识到了docker的启动流程。
由于篇幅限制,把 Dockerfile 的内容在拆出一篇来进行说明,以及把遇到的一些问题也进行一些整理。
我的docker环境:
https://github.com/helei112g/docker-env
以后换机装换机,再也不担心了
参考资料:
推荐阅读
Dockerfile 你真的会写吗?编写Dockerfile的最佳实践
喜欢本文的朋友,欢迎关注“Go语言中文网”:
Go语言中文网启用微信学习交流群,欢迎加微信:274768166