美文网首页程序员
用好docker,让自己的环境跳起舞来

用好docker,让自己的环境跳起舞来

作者: 玩物励志老乐 | 来源:发表于2020-08-23 12:32 被阅读0次

    2020年了,相信大部分技术同学的开发环境都是基于docker搭建了。如果是,希望我的文章能给你带来新的收获;如果不是,那你更应该看看,了解一下为什么用docker可以让环境优雅的跳起舞来。

    一般来说,我们使用docker容器技术搭建环境,有3种做法。

    1. 基础做法

    先从docker hub上面,下载一个centos7.x镜像。然后再依次在上面安装各种服务,如nginx, MySQL, PHP或Python等,这种做法就跟你拿到一个新的vagrant或virtualbox实例时是一样的。这几乎没有什么额外的学习成本。

    1000年过去了,终于所有的服务都安装好了,配置完了,通过了环境测试,我们才能开始编码。在使用docker之前,我身边的开发同学折腾环境经常会花费整整一天的时间,非常耽误事。而当某些原因的出现,导致你需要再次折腾环境时,就得再来一次刚才的操作。对此运维同学一定感同深受,那种做着重复机械但别人又做不来的工作时的内心,一定是崩溃的。

    docker hub的存在,让服务器环境也有了托管平台。为了以后安装环境方便,我们可以把自己折腾过的自己的定制环境,提交发布到hub.docker.com。(做法可以见我之前的文章: 如何将自己的容器提交到docker.com?

    然而......有时候我们会发现,用基础做法“魔改”出来的这种镜像,未必适合我们下一个项目的需求。难道我们还要再折腾一天吗?如果每个项目的环境都有差异,那么我们都得永无止境的折腾吗?

    折腾永无止境.jpg

    2.使用Dockerfile,定制自己的基础镜像

    答案当然是“No”,因为我们可以使用Dockerfile,像开发同学编码一样来定制我们的服务器环境。而Dockerfile的语法也很简单,本文也提供了一个简单的讲解和例子供你参考。

    需要说明的是,这种做法并不能完全将我们从服务环境搭建中解放出来。因为Dockerfile在设计初衷,就是为了在社区分享用的。所以类似端口映射,本地目录加载等个性化配置,是没办法写在Dockerfile里的。这就意味着,你虽然写好了一个镜像,但仍然需要很长一串加载命令。比如下面这行代码,基于某镜像的某个版本,映射常用的80,443和3306端口,加载本地的代码目录。这是非常普通的写法,实际情况可能会比这个更恶劣。

    docker run -it -p 80:80/tcp,443:443/tcp,3306:3306/tcp -v /path/to/code:/var/www --names my_docker_env docker_image:version
    

    总之,使用Dockerfile比自己运行大量的yum install(或apt-get install)命令要优雅的多。学会了Dockerfile,你可以很优雅的,像写代码一样,几分钟就把自己想要的镜像脚本写好了。剩下的事情就是让电脑代替自己去工作了,你可以悠闲的喝杯咖啡,翘起二郎腿,和自己心仪的妹子打情骂俏了。(如果有的话...... doge狗头保命)


    咖啡和远方.jpg

    3. 使用docker-compose让环境自己跳起舞来。

    开发同学经常挂在嘴边的话就是要高内聚,低耦合。我们的开发环境也是能做到低耦合的。不同于以上两种将所有服务都塞进一个镜像容器的做法,这种做法使用了N个独立的镜像,比如MySQL镜像、Laravel镜像、nginx镜像等等,然后通过docker-compose的配置,让他们协作起来。

    因为docker本身不是虚拟机,而是容器服务。就跟LOGO一样,是驮着集装箱的鲸鱼。集装箱有多少,箱里有多少货物,都是与鲸鱼无关的。每次遇到不同的项目需求,我们都可以随意增减集装箱,让这些容器就想插销一样,拔掉2个,插上1个,就能满足需要了。可以说,学会方法3才是真正发挥了docker最大优势,才是你可以拍胸膛说,“我会docker”。

    docker.jpg

    怎么才能做到呢?

    下面我会以自己的情况进行举例。我有2个自己魔改的镜像,一个是运行了nginx+php7+laravel的php开发环境,另一个则是运行了nginx+python+django的python开发环境。由于他们会用到相同的数据库,所以还有一个独立于他们的mysql数据库镜像(其实也是最简单的服务器结构,即数据与业务分离)。每次启动时,必须先启动mysql,再启动其他环境。我们的目标是:每次电脑(宿主机)重启之后,只需要让那只鲸鱼游起来,环境就直接可以使用

    我们的目标是...

    我们需要学习两个方面的技能,即方法2提到的Dockerfile和方法3提到的docker-compose。

    什么是dockerfile?为什么要学习dockerfile?

    dockerfile是docker容器技术的核心,几乎每一个docker镜像都是由dockerfile构建而成的。举个栗子:

    FROM shingler/php7_laravel_nginx:v2
    MAINTAINER singlerwong@qq.com
    RUN apt-get install -y vim \
        && ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
        && echo 'Asia/Shanghai' > /etc/timezone
    VOLUME /var/www
    WORKDIR /var/www
    COPY gfapi.conf /etc/nginx/conf.d
    EXPOSE 8100
    CMD /etc/init.d/nginx start & /etc/init.d/php7.0-fpm start & /bin/bash
    

    上面的例子做了以下事情:基于我的魔改镜像,在启动时先安装一个vim。然后将/var/www作为目录挂载点(为了挂载本地代码目录),将当前工作目录设定为/var/www,将宿主机的现成的nginx配置拷贝到docker镜像的nginx配置目录里,同时暴露8100端口,供开发测试使用。

    这里面包含了几个非常重要的命令,简述如下:

    1. FROM
    • 你的镜像是基于哪个镜像构建的,有点像我们开发编程中的继承的概念;
    1. RUN
    • 镜像构建时运行什么命令,一般都用来安装工具或依赖服务。比如我这里安装了vim;
    1. VOLUME
    • 设定目录挂载点。让用于将宿主机的代码目录挂载在服务器上的nginx识别的web目录。格式是宿主机代码目录 + “:” + 服务器目录;
    1. WORKDIR
    • 切换工作目录。如果你也想我一起要运行COPY命令,切换了WORKDIR你就可以少写前面的绝对路径了;
    1. COPY
    • 你可以让镜像在构建时,就将提前准备好的php-fpm,hosts等配置覆盖进去了;
    1. EXPOSE
    • 对外暴露什么端口。只有你暴露什么端口,才能映射什么端口;
    1. CMD
    • 镜像启动时运行的命令。不同于RUN,RUN是构建时,CMD是启动时。比如我的例子里就启动了nginx和php-fpm命令。运行一个/bin/bash能够让你的容器一直处于运行状态,否则运行完,容器就退出了;
    1. ENTRYPOINT
    • 和CMD相似,不同的是,如果你运行docker run后制定了cmd参数,dockerfile里的cmd会被覆盖(主要是挂起的那步)。entrypoint则不会,你可以继续在后面跟参数,比如
    ENTRYPOINT ps -aux
    

    这样你就可以在后面跟上grep管道过滤某些字符了。

    这样的dockerfile,可以让我每次电脑重启时,不用手动修改配置了。但是运行docker run的时候,那长长的参数(目录挂载,端口映射)依然无法省略。独立的mysql容器启动之后,我还必须使用docker inspect查看mysql容器的ip地址,再去代码里修改mysql的配置项。

    Dockerfile里的run命令我增加了对宿主机时间的软链接。可以有效解决docker环境与宿主机时间不一致的问题。

    写好了之后,别忘记构建哦(注意运行在Dockerfile存在的目录。最后的.很重要)

    docker build -t 镜像名:版本号 .
    

    什么是docker-compose?为什么要学习docker-compose?

    composer.jpg

    在音乐界,compose是编曲的意思。曾经有人说,会作词的没有会作曲的厉害,会作曲的没有会编曲的厉害。docker-compose就是这么一个能够编排docker镜像的工具。

    通过docker compose,我们不但可以告别长长的启动参数,还可以让他们按照制定的顺序(比如先启动mysql容器再启动php容器)启动,并且固定他们的虚拟IP地址。

    看下面的例子:

    version: "2"
    services:
      laravel:
        image: laravel_dev:1.7            # 加载镜像名及指定版本。
        restart: always                   # 容器退出后自动重启。
        depends_on:                       # 该容器依赖于哪个容器(指定启动顺序的关键)
          - mysql
        volumes:                          # 挂载代码目录
          - /Users/shingler/project:/var/www
        container_name: my_laravel_dev    # 给容器起个中二的名字
        tty: true                         # 进入容器时能够用linux命令操作
        ports:                            # 端口映射
          - 8100:8100
        expose:                           # 端口暴露
          - 8100
        links:                            # 服务名,并写入hosts里。配置了这个,基本上我们就不再需要修改代码里mysql的ip地址了。
          - "mysql:gf-mysql"
        networks:                         # 使用的网络配置,可以用于固定ip地址
          my_dev_workspace:
            ipv4_address: 172.18.0.2
    
      # 省略django配置,和laravel大同小异
    
      mysql:
        image: mysql:5.6
        restart: always
        volumes:
          - /Users/shingler/database:/var/lib/mysql
        container_name: mysql56
        ports:
          - 3306:3306
        expose:
          - 3306
        environment:                     # 设置环境变量,对于mysql可以用来设置root的密码
          MYSQL_ROOT_PASSWORD: 123456
        networks:
          my_dev_workspace:
            ipv4_address: 172.18.0.3
    
    networks:                            # 配置网络项,要顶格写
      my_dev_workspace:                  # 网络配置名 
        driver: bridge                   # 网络连接方式
        ipam:
          driver: default
          config:
          - subnet: 172.18.0.0/16        # 网段
            gateway: 172.18.0.1          # 网关ip
    

    做好之后,可以运行以下命令,完成构建。

    docker-compose up -d
    

    从此之后,宿主机重启后,启动小鲸鱼,开发环境自己就跳起舞啦。如果需要增加服务,在docker-compose里,仿照上面的laravel的配置,写写就可以了。

    芭蕾舞.jpg

    写在最后

    虽说懒惰使人进步,但我们节约下来的时间和精力,绝不是要用来懒着,不能为了偷懒而偷懒。合理利用自己的时间精力,专注于更能创造价值的活动,才能做到我们的进步,是源于我们的懒惰。

    希望我的文章,对你有所帮助。喜欢的话,不妨点个关注,点个赞吧!

    相关文章

      网友评论

        本文标题:用好docker,让自己的环境跳起舞来

        本文链接:https://www.haomeiwen.com/subject/nlzfjktx.html