以前一直使用 Vagrant 作为自己的开发环境,并且在上家公司也推行大家采用 Vagrant 作为开发环境,保障公司使用的是同一套开发环境。随着docker的流行,越来越多的人在docker上运行自己的项目,利用docker也非常方便模拟各种线上集群,相比虚拟机效率会更高,不管是搭建还是运行。

网络上关于docker搭建环境的资料非常之多了,但自己一直没有进行过实践。纸上得来终觉浅,只有自己动过手之后,才能对相关的概念更熟悉。花了将近2天时间折腾,终于算是把docker的开发环境搭建好了,对他的很多概念也又了更深入的认识。整理一下整个过程,方便以后查漏补缺。

下面就来开启docker之旅吧,打算利用docker完成以下任务:
- 基础的环境搭建:MySQL、Redis、Nginx;
- 搭建PHP、Golang的开发环境;
- 搭建MySQL、Redis的主从;
- 探索一下如何监控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

以后换机装换机,再也不担心了

微信公众号:
pub

参考资料:
- https://yeasy.gitbooks.io/docker_practice/content/

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐