前端的Docker入门与实践

栏目: 编程工具 · 发布时间: 5年前

内容简介:本文内容还是相对很浅的,Docker中关于分布式,集群的内容没有涉及,所以本文推荐前端同学看一看,后端同学就不推荐了。本文中所有命令都是针对本文主要参考了以下资料命令汇总,方面快速查询
前端的 <a href='https://www.codercto.com/topics/20577.html'>Docker</a> 入门与实践

感谢 & 参考

本文内容还是相对很浅的,Docker中关于分布式,集群的内容没有涉及,所以本文推荐前端同学看一看,后端同学就不推荐了。本文中所有命令都是针对 Ubuntu16.04 ,拷贝粘贴时请注意。( 这一篇文章有些复读机:trumpet:,对docker感兴趣的可以直接看以下的参考资料 )

本文主要参考了以下资料

命令汇总

命令汇总,方面快速查询

# 创建镜像
docker build -t [镜像名] .
# Docker镜像列表
docker image ls
# 删除镜像
docker rmi [id]
# 删除所有的镜像
docker image rm $(docker image ls -a -q)

# Docker容器列表
docker container ls
docker container ls --all
# 全部的停止的容器
docker container ls -aq
# 删除容器
docker rm [id]
# 删除所有的容器
docker container rm $(docker container ls -a -q)
# 停止容器
docker container stop [id]
# 启动停止的容器
docker container start [id]
# 强制关闭指定容器
docker container kill [id]
# 重启容器
docker container restart [id]
# 进入容器内部
docker exec -it [容器id] bash


# 运行容器,外部的4000端口映射到容器的80端口
docker run -p 4000:80 hello
# 指定容器的名称 --name
docker run --name [name] -p 4000:80 [image]
# 守护态运行容器(后台运行,不需要在打开一个终端)
docker run -d -p 4000:80 hello
# 随机映射本机的端口到容器的端口
docker run -d -P [image]
# 映射所有的地址
docker run -d -p [宿主机端口]:[容器端口] [image]
# 映射指定地址以及端口
docker run -d -p [ip]:[宿主机端口]:[容器端口] [image]
# 映射指定地址的任意端口
docker run -d -p [ip]::[容器端口] [image]
# 查看容器映射的端口
docker port [容器名|容器id] [容器的端口]


# 标记镜像
docker tag [镜像名] [用户名]/[存储库]:[标签]
# 上传镜像到DockerHub
docker push [用户名]/[存储库]:[标签]
# 从DockeerHub上获取镜像
docker pull [存储库]:[标签]
# 从存储库运行镜像
docker run -p [用户名]/[存储库]:[标签]

# 创建数据卷
docker volume create [数据卷名称]
# 查看所有的数据卷
docker volume ls
# 查看数据卷的信息
docker volume inspect [数据卷名称]
# 删除数据卷
docker volume rm [数据卷名称]
# 清理无主的数据卷
docker volume prune

# 查看网络列表
docker network ls
复制代码

Docker的基本概念

前端的Docker入门与实践
前端的Docker入门与实践

Docker的虚拟化是在系统层面实现的,虚拟机则是在硬件方面实现的。

镜像

Docker Images 是一个可执行的包。包含了运行应用程序的所有内容,代码,运行时,环境变量,库,配置文件。

镜像的构成

镜像的构建是一层层构建的,前一层是后一层的基础。每一层构建完成后,不会再改变。后面的修改的只会发生当前的镜像层。比如删除前一层的文件,并不是真正的删除。而是在后面的镜像层中标记为删除,删除的文件会一直存在镜像中。

分层的特性使得镜像容易扩展和复用。比如在Docker Hub上提供的各种基础镜像。

前端的Docker入门与实践

commit

我们在上面说过镜像是分层的。我们这里利用commit命令深入理解下镜像的构成。

我们使用 docker run --name webserver -d -p 4880:80 nginx 构建nginx的容器。使用 exec 进入webserver容器,并进行了一定的修改。而docker commit命令可以将我们对容器存储层的修改保存下来,成为新的镜像。新的镜像由原有的镜像,加上我们更改的存储层构成的。

容器

Docker Containers 是镜像运行的实例。可以使用docker ps查看正在运行的容器列表。容器同样也是多层存储,以镜像作为基础层,在基础层上加一层容器运行的存储层。

Docker安装

卸载旧版本的Docker

sudo apt-get remove docker docker-engine docker.io containerd runc
复制代码

安装

# 更新apt
sudo apt-get update

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

# 添加官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# 将存储库添加到APT源
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# 更新apt
sudo apt-get update

# 安装
sudo apt-get install docker-ce docker-ce-cli containerd.io
复制代码

验证安装

# 查看docker版本
docker version
复制代码
前端的Docker入门与实践
# 允许hello-world镜像,验证是否正确安装
docker run hello-world
复制代码

容器

在过去如果要编写 Python 应用程序,需要在机器上安装Python运行时,不仅仅需要在你的开发机器配置环境,而且还需要在生产环境的机器上配置环境。如果使用Docker,可以把Python运行时通过镜像获取,无需在不同的机器上重复安装环境。可以在应用程序,和Python运行时镜像打包在一起。确保在不同的机器上都可以正常运行。这些可移植的镜像,由Dockerfile定义

Dockerfile

Dockerfile定义了容器内的环境。容器与系统的其他部分相隔离,因此需要将容器的端口映射到外部。由这个Dockerfile定义的应用程序的构建,运行在任何地方的行为都完全相同。

示例

# 创建空文件夹,并在文件夹中创建Dockerfile文件
mkdir learn-docker
cd learn-docker
touch Dockerfile
touch app.js
复制代码

Dockerfile

# 在Dockerfile写入以下的内容
vim Dockerfile

# 将node作为父镜像
FROM node
# 将容器的工作目录设置为/app(当前目录,如果/app不存在,WORKDIR会创建/app文件夹)
WORKDIR /app
# 将当前文件夹中的所有内容,复制到容器的/app中
COPY . /app
# 安装node包
RUN npm install 
# 容器对外暴露80端口
EXPOSE 80
# 环境变量
ENV NAME World
# 容器启动时运行app.js
CMD ["node", "app.js"]
复制代码

app.js

const express = require('express')
const app = express()

app.get('/', function (req, res) {
  res.send('hello world')
})

app.listen(80, '0.0.0.0')
复制代码

我们并不需要在系统中安装Python,Flask或者Redis。构建运行镜像的时候也不需要安装它们。虽然看起来我们没有使用Pyhone构建开发环境,但是我们已经这样做了。

构建应用程序

使用docker build命令,构建镜像。(--tag选项会对镜像进行命名)

# 构建hellodocker的镜像
docker build --tag=hellodocker .

# 构建完成后,我们查看镜像列表
docker image ls
复制代码
前端的Docker入门与实践

运行应用程序

# 将服务器的4000端口映射到容器的80端口
docker run -p 3999:80 hellodocker

# 查看正在运行的容器
docker container ls

# curl测试,返回helloworld
curl 0.0.0.0:3999
复制代码
前端的Docker入门与实践
前端的Docker入门与实践

Dockerfile指令详解

:star2:FROM

FROM指令用于指定镜像的基础镜像。 FROM scratch ,可以指定空的基础镜像。

:star2:RUN

Dockerfile中每一个指令都会建立一层镜像, 不应该把RUN指令当作 shell 脚本来写

FROM scratch

# 这回额外的创建7层镜像,这是错误的行为
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install


# 正确的写法应当是,使用&&将命令串连,简化为一层镜像
RUN buildDeps='gcc libc6-dev make wget' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    # 清除无用的缓存,避免Docker的臃肿
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps
复制代码

COPY

COPY指令将当前目录的文件,复制到image中。

源路径指的是当前上下文的目录。目标路径可以是容器内的绝对路径路径,也可以是容器 WORKDIR 指定的工作目录的相对路径。

COPY [源路径] [目标路径]
复制代码

CMD

CMD指定容器主进程的启动命令。

# 使用node
CMD ["node", "app.js"]

# 使用pm2
# http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/#docker-integration 
RUN npm install pm2 -g
CMD ["pm2-runtime", "app.js"]
复制代码

VOLUME

VOLUME指令可以指定某个目录为 匿名卷 ,任何对该目录的写操作,不会记录到容器的存储层。

对于数据库,数据库文件应保存到数据卷中

VOLUME /data
复制代码

ENV

ENV指令用来设置环境变量,Dockerfile后面的指令或者代码中,都可以使用该环境变量

# Dockerfile
# 环境变量
ENV NAME World
复制代码
// app.js
const express = require('express')
const app = express()

app.get('/', function (req, res) {
  // 使用环境变量
  res.send(`hello world${process.env.NAME}`)
})

app.listen(80, '0.0.0.0')
复制代码

EXPOSE

EXPOSE指令用于声明端口,但是EXPOSE声明的端口要和docker run <宿主端口>:<容器端口>区分。EXPOSE指令 仅仅是声明 ,而不会自动进行端口映射。

WORKDIR

WORKDIR用来指定 当前目录(工作目录) ,Dockerfile不是shell脚本,这一点需要切记。

# 这是错误的示范
RUN cd /app
RUN echo "hello" > world.txt
复制代码

这里并不会创建 /app/world.txt的文件。因为在Dockerfile中两行RUN的执行环境是不同的。所以第一层的 cd /app 不会影响到第二层的当前目录,正确的做法应当是。

WORKDIR /app
RUN echo "hello" > world.txt
复制代码

分享你的镜像

什么是DockerHub?

DockerHub类似于Github,由Docker官方维护的一个公共容器镜像仓库。我们首先注册,并登录Docker Hub

创建存储库

前端的Docker入门与实践

标记镜像

# 登录
docker login

# 标记镜像
# docker tag [镜像名] [用户名]/[存储库]:[标签]
docker tag hellodocker zhangyue9467/learn-docker:test
复制代码
前端的Docker入门与实践

发布镜像

docker push zhangyue9467/learn-docker:test
复制代码

Docker Hub仓库中就会有我们发布的镜像

前端的Docker入门与实践

从DockerHub拉取并运行镜像

使用Docker后,我们不需要在其他机器上安装任何东西,就可以运行它。只需要远程拉取Docker的镜像

docker run -p 3998:80 zhangyue9467/learn-docker:test
复制代码

数据卷

什么是数据卷?

数据卷是一个可供一个或多个容器使用的特殊目录, 数据卷中的数据可以容器之间共享和重用。对数据卷的修改会立马生效。

创建数据卷

# 创建一个名为vol的数据卷
docker volume create vol

# 查看数据卷中的信息
docker volume inspect vol 
复制代码
前端的Docker入门与实践

Mountpoint中是数据卷挂载在宿主机的位置。我们在Mountpoint字段对应的文件夹内创建一个文件

前端的Docker入门与实践

启动挂载了数据卷的容器

使用--mount,在启动容器时挂载数据卷,容器启动时可以挂载多个数据卷。

# 启动了name为web的容器
# 使用vol数据卷,加载到容器的/webapp中

docker run -d -P \
    --name web \
    --mount source=vol,target=/webapp \
    hello
复制代码
前端的Docker入门与实践

进入web容器进行查看,vol数据卷中内容挂载到容器的/webapp目录中

前端的Docker入门与实践

挂载宿主机目录作为数据卷

宿主机的路径必须是绝对路径,使用--mount如果主机目录不存在Docker会报错。Docker默认对主机目录的权限是读写权限。

# 启动了name为web2的容器
# 使用本机/var/www/vol目录作为数据卷,加载到容器的/webapp中

docker run -d -P \
    --name web2 \
    --mount type=bind,source=/var/www/vol,target=/webapp \
    hello
复制代码
前端的Docker入门与实践

挂载本地文件作为数据卷

# /root/.bash_history 作为卷

docker run -d -P \
    --name web3 \
    --mount type=bind,source=/root/.bash_history,target=/root/.bash_history \
    hello
复制代码
前端的Docker入门与实践

在容器内部可以获取外部的命令行的历史记录

网络

外部访问容器

# 映射任意端口到容器的端口
docker run -d -P [image]

# 映射所有的地址
# docker run -d -p 5000:5000 web
docker run -d -p [宿主机端口]:[容器端口] [image]

# 映射指定地址以及端口
# docker run -d -p 127.0.0.1:5000:5000 web
docker run -d -p [ip]:[宿主机端口]:[容器端口] [image]

# 映射指定地址的任意端口
# docker run -d -p 127.0.0.1::5000 web
docker run -d -p [ip]::[容器端口] [image]
复制代码

查看容器映射端口配置

# 查看容器映射的端口
docker port [容器名|容器id] [容器的端口]
复制代码
前端的Docker入门与实践

容器内部拥有自身的网络和ip,可以使用docker inspect命令在"NetworkSettings"中获取。

# 查看容器内部的ip信息
docker inspect [容器id]
复制代码
前端的Docker入门与实践

容器通信

使用自定义Docker网络实现容器通信。如果是多个容器可以使用Docker Compose实现容器间的通讯,Docker Compose默认所有容器都在同一个网络中的。

# 创建网络
docker network create -d bridge mynet

# 将容器链接到网络mynet中
docker run -d -p 5000:8888 --name busybox1 --network mynet hello
docker run -d -p 5001:8889 --name busybox2 --network mynet hello2

# 进入容器busybox1内部,可以使用curl或者ping,测试

# busybox2的ip地址
curl 172.19.0.3:8889
# 
ping busybox2
复制代码
前端的Docker入门与实践

Docker Compose

什么是Compose?

使用Dockerfile文件可以很方便定义一个容器。但在日常的工作中一个项目可能需要多个容器(前端,后端,数据库)。Compose允许用户定义docker-compose.yml模版文件,来定义一组相关联的容器为一组项目。

Compose中两个概念:

  • 服务(service),一个应用的容器,可以是多个相同镜像的实例。
  • 项目(project),一组关联的应用容器组成的完整业务单元, 在docker-compose.yml中定义

Compose安装

sudo curl -L https://github.com/docker/compose/releases/download/1.17.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose
复制代码

验证docker composc的安装

# 查看版本

docker-compose --version
复制代码

Compose命令

更多命令请参考。

:bulb:在介绍Compose命令之前,我觉得有必要明确一下,服务与容器的概念。我曾经混淆过它们的概念,详细的解答请参考

在docker-compose中,docker-compose.ymal中定义的是 服务 , 下面定义了一个名为 web 的服务。而web的服务会启动一个名为"[项目文件的名称]_web"的容器。

# docker-compose.ymal

version: '3'
services:
  web:
    build: .
    ports:
     - "5000:3000"
复制代码

build

在项目的目录根目录下运行build命令,构建镜像

# 构建容器
docker-compose build
复制代码
前端的Docker入门与实践

ps

在项目的根目录下运行ps命令,列出 项目中 的所有容器

docker-compose ps
复制代码
前端的Docker入门与实践

up

up命令将会完成构建容器,创建服务,启动服务,等一系列操作。可以直接通过up命令启动一个项目

# 在前台启动容器
docker-compose up

# 在后台启动并运行项目(不需要强制退出控制台了)
docker-compose up -d
复制代码

port

查看 服务 映射在宿主机上的端口

version: '3'
services:
  web:
    build: .
    ports:
     - "5000:3000"
复制代码
# 示例
# 0.0.0.0:5000
docker-compose port web[服务] 3000[容器端口]
复制代码

Compose模板文件

更多指令请参考

version: '3'
services:
  # web服务
  web:
    # 容器的名称
    container_name: hello_compose
    # Dockerfile文件的位置(绝对路径,相对docker-compose模版文件的路径都可以)
    build: .
    # 暴露端口,但不映射到宿主机
    expose:
     - "3000"
    # 暴露端口 [宿主端口]:[容器端口]
    ports:
     - "5000:3000"
    # 数据卷挂载的路径
    # https://forums.docker.com/t/making-volumes-with-docker-compose/45657
    volumes:
     - [宿主机路径]:[容器路径]
  # db服务
  db:
    # 容器使用的镜像
    image: "redis:alpine"
复制代码

实战

Docker部署前端应用

前端的Docker入门与实践

新建jenkins任务,将github上的项目拉取到线上云服务器的空文件夹中。

接着定义Dockerfile自定义镜像。使用FROM指令将nginx作为父镜像,使用COPY指令将上下文目录的所有内容拷贝到容器的/var/www/hello_docker/目录中。/var/www/hello_docker/是我们在nginx配置中配置的静态文件目录。接着使用COPY指令将nginx的配置文件,拷贝到/etc/nginx/conf.d/目录中。conf.d文件夹内的nginx配置文件的内容,会合并到nginx主配置文件中。紧接着使用RUN指令重启nginx服务。

使用Dockerfile自定义我们的镜像后,需要通过build命令构建我们的镜像。由于需要做到运维的自动化,直接启动我们的镜像可能会产生错误(可能存在同名的镜像)。我们使用shell脚本判断是否需要删除之前的镜像还是直接启动容器。最后使用run命令构建我们的容器。

# Dockerfile

FROM nginx
COPY ./* /var/www/hello_docker/
COPY ./nginx/hello_docker.conf /etc/nginx/conf.d/
RUN service nginx restart
复制代码
# nginx.conf
server {
    listen 8888;
    server_name localhost;

    root /var/www/hello_docker;
    index index.html;
    expires      7d;
}
复制代码

容器构建完成后,我们在本地无法直接访问容器映射的接口,我们需要在:cloud:云服务器配置nginx代理,访问容器。

前端的Docker入门与实践

(我们将转发请求到容器映射的接口上)

Docker部署Node服务

前端的Docker入门与实践

前端的部署同之前的项目一致(这里略过)。使用Dockerfile定义后端服务镜像,使用FROM指令将node作为父镜像,使用RUN指令在全局安装pm2,使用CMD指令, 使用pm2启动后端的服务。

FROM node

WORKDIR /server

COPY . /server
    
EXPOSE 8888

RUN npm install pm2 -g

CMD ["pm2-runtime", "app.js"]
复制代码
前端的Docker入门与实践

Docker部署Mongo

我们直接使用docker-compose部署mongo数据库。

需要注意的是,mongo数据存储的位置,不建议直接将数据直接存储到容器中。而是使用volumes,将容器内数据库的存储目录挂载到宿主机的目录中

version: '3.1'

services:
  mongo:
    # 使用docker hub 的mongo镜像
    image: mongo
    # 容器重启策略
    restart: always
    # 容器启动的参数
    command:
      - '--auth'
      - '-f'
      - '/etc/mongod.conf'
    # 指定数据卷,配置文件以及数据存储的位置
    volumes:
      - '/etc/mongod.conf:/etc/mongod.conf'
      - '/var/lib/mongodb:/var/lib/mongodb'
    ports:
      - '37017:27017'
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Clean Architecture

Clean Architecture

Robert C. Martin / Prentice Hall / 2017-9-20 / USD 34.99

Practical Software Architecture Solutions from the Legendary Robert C. Martin (“Uncle Bob”) By applying universal rules of software architecture, you can dramatically improve developer producti......一起来看看 《Clean Architecture》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具