内容简介:本文内容还是相对很浅的,Docker中关于分布式,集群的内容没有涉及,所以本文推荐前端同学看一看,后端同学就不推荐了。本文中所有命令都是针对本文主要参考了以下资料命令汇总,方面快速查询
感谢 & 参考
本文内容还是相对很浅的,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 Images 是一个可执行的包。包含了运行应用程序的所有内容,代码,运行时,环境变量,库,配置文件。
镜像的构成
镜像的构建是一层层构建的,前一层是后一层的基础。每一层构建完成后,不会再改变。后面的修改的只会发生当前的镜像层。比如删除前一层的文件,并不是真正的删除。而是在后面的镜像层中标记为删除,删除的文件会一直存在镜像中。
分层的特性使得镜像容易扩展和复用。比如在Docker Hub上提供的各种基础镜像。
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 复制代码
# 允许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 复制代码
运行应用程序
# 将服务器的4000端口映射到容器的80端口 docker run -p 3999:80 hellodocker # 查看正在运行的容器 docker container ls # curl测试,返回helloworld curl 0.0.0.0:3999 复制代码
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 login # 标记镜像 # docker tag [镜像名] [用户名]/[存储库]:[标签] docker tag hellodocker zhangyue9467/learn-docker:test 复制代码
发布镜像
docker push zhangyue9467/learn-docker:test 复制代码
Docker Hub仓库中就会有我们发布的镜像
从DockerHub拉取并运行镜像
使用Docker后,我们不需要在其他机器上安装任何东西,就可以运行它。只需要远程拉取Docker的镜像
docker run -p 3998:80 zhangyue9467/learn-docker:test 复制代码
数据卷
什么是数据卷?
数据卷是一个可供一个或多个容器使用的特殊目录, 数据卷中的数据可以容器之间共享和重用。对数据卷的修改会立马生效。
创建数据卷
# 创建一个名为vol的数据卷 docker volume create vol # 查看数据卷中的信息 docker volume inspect vol 复制代码
Mountpoint中是数据卷挂载在宿主机的位置。我们在Mountpoint字段对应的文件夹内创建一个文件
启动挂载了数据卷的容器
使用--mount,在启动容器时挂载数据卷,容器启动时可以挂载多个数据卷。
# 启动了name为web的容器 # 使用vol数据卷,加载到容器的/webapp中 docker run -d -P \ --name web \ --mount source=vol,target=/webapp \ hello 复制代码
进入web容器进行查看,vol数据卷中内容挂载到容器的/webapp目录中
挂载宿主机目录作为数据卷
宿主机的路径必须是绝对路径,使用--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 复制代码
挂载本地文件作为数据卷
# /root/.bash_history 作为卷 docker run -d -P \ --name web3 \ --mount type=bind,source=/root/.bash_history,target=/root/.bash_history \ hello 复制代码
在容器内部可以获取外部的命令行的历史记录
网络
外部访问容器
# 映射任意端口到容器的端口 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] [容器的端口] 复制代码
容器内部拥有自身的网络和ip,可以使用docker inspect命令在"NetworkSettings"中获取。
# 查看容器内部的ip信息 docker inspect [容器id] 复制代码
容器通信
使用自定义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 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 复制代码
ps
在项目的根目录下运行ps命令,列出 项目中 的所有容器
docker-compose ps 复制代码
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部署前端应用
新建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部署Node服务
前端的部署同之前的项目一致(这里略过)。使用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部署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' 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。