凉城旧巷
Python从入门到自闭,Java从自闭到放弃,数据库从删库到跑路,Linux从rm -rf到完犊子!!!

Docker 部署项目

一、安装docker(Ubuntu)

转自:https://blog.csdn.net/jinking01/article/details/82490688

  • 由于apt官方库里的docker版本可能比较旧,所以先卸载可能存在的旧版本:
$ sudo apt-get remove docker docker-engine docker-ce docker.io
  • 更新apt包索引:
$ sudo apt-get update
  • 安装以下包以使apt可以通过HTTPS使用存储库(repository):
$ sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
  • 添加Docker官方的GPG密钥:
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
  • 使用下面的命令来设置stable存储库:
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
  • 再更新一下apt包索引:
$ sudo apt-get update
  • 安装最新版本的Docker CE:
$ sudo apt-get install -y docker-ce
  • 验证docker
$ systemctl status docker

docker正常启动,状态如下图:

  • 若未启动,则启动docker服务:
$ sudo systemctl start docker
  • 查看docker版本号验证
$ sudo docker -v

二、docker仓库配置

1、设置公有仓库

  • 修改仓库配置文件
$ vim /etc/docker/daemon.json

{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}
  • 重启docker
$ systemctl daemon-reload 
$ systemctl restart docker

常用国内加速站点:

https://registry.docker-cn.com			国内
http://hub-mirror.c.163.com				网易
https://3laho3y3.mirror.aliyuncs.com		阿里
http://f1361db2.m.daocloud.io
https://mirror.ccs.tencentyun.com

2、设置私有仓库

参考:https://www.cnblogs.com/xiao987334176/p/9946915.html

1)搭建私有仓库——私有服务器上

  • 搭建工具

docker 官方提供了 registry 的镜像,可以使用它来建私有仓库。

  • 环境
系统 IP 角色
Ubuntu 18.04 10.0.0.0 docker 客户端服务器
Ubuntu 18.04 10.0.0.1 docker 仓库服务器(root用户)
  • 都安装docker,修改docker源,并重启(参考一)

  • 在10.0.0.1上拉取registry

    docker pull registry
    
  • 在10.0.0.1上启动仓库

    docker run -d --name docker-registry --restart=always -p 5000:5000 registry
    

2)设置私有仓库

  • 客户端10.0.0.0设置私有仓库地址,并重启

    $ vim /etc/docker/daemon.json
    
    {
      "registry-mirrors": ["https://registry.docker-cn.com"],
      "insecure-registries": ["10.0.0.1:5000"]		# 设置私有仓库地址
    }
    
    systemctl restart docker
    
  • 测试私有仓库

    在10.0.0.0下载一个镜像,如alpine

    sudo docker pull alpine
    

    打tag,镜像名称由registry和tag两部分组成,registry完整格式:[registry_ip]:[registry:port]/[user]/[image_name:version]

    sudo docker tag alpine 10.0.0.1:5000/alpine
    
  • 上传本地镜像

    sudo docker push 10.0.0.1:5000/alpine
    
  • 查看仓库镜像

    curl 10.0.0.1:5000/v2/_catalog
    

三、拉取镜像

1、登录仓库

sudo docker login -u [user] -p [password] [ip:port]
  • user 仓库用户名
  • password 仓库密码
  • ip:port为仓库地址

2、拉取镜像

sudo docker pull [image_name]

四、dockerfile编写

在项目目录下创建Dockerfile文件

参考:https://www.cnblogs.com/cloudfloating/p/11737447.html

1、RUN

RUN 指令是用来执行命令行命令的。RUN 指令的格式有两种:

  • shell 格式:RUN <命令>,就像直接在命令行中输入命令一样。

    RUN java -jar app.jar
    
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"]

    RUN ["java", "-jar", "app.jar"]
    

Dockerfile 中,每一个指令都会在镜像上建立一层,所以对于多个命令行,不要写多个 RUN 指令

多个命令,在一个RUN中实现,使用 **&& **连接起来

FROM ubuntu

RUN apt-get update \
    && apt-get install -y redis

2、COPY

COPY 指令用来将宿主的文件目录复制到镜像中。有两种格式:

  • COPY [--chown=<user>:<group>] <源路径>... <目标路径>

    COPY app.jar /usr/src/
    
  • COPY [--chown=<user>:<group>] ["源路径1", ... "目标路径"]

    COPY ["app.jar", "config.yml", "/usr/src"]
    

对于多个路径参数,最后一个为目标路径其他都是源路径目标路径 可以是绝对路径,也可以是相对于工作目录的路径(工作目录可以用 WORKDIR 来指定)。目标路径如果不存在,在复制文件前会先创建。

3、CMD

CMD 是容器启动命令,它指定了容器启动后要执行的程序。与 RUN 指令相似有两种形式:

  • shell 格式:CMD <命令>

    CMD echo 'Hello, world!''
    
  • exec 格式:CMD ["可执行文件", "参数1", "参数2", ...]

    CMD [ "sh", "-c", "echo 'Hello, world!'" ]
    

还有一种参数列表格式:CMD ["参数1", "参数2", ...]。在指定了 ENTRYPOINT 指令后,可以用 CMD 指定参数。

在使用 CMD 时,程序必须以前台运行,Docker 不是虚拟机,容器没有后台服务的概念。如果使用 CMD 运行一个后台程序,那么容器在命令执行完就会退出。

CMD java -jar app.jar &

以上命令让 app.jar 在后台运行,容器启动后就会立刻退出。Docker 容器与守护线程很相似,当所有前台程序退出后,容器就会退出。

CMD 指定的命令可以在运行时替换,跟在镜像名称后面的参数将替换镜像中的 CMD

docker run app echo $HOME

以上命令运行容器时使用 echo $HOME 替换掉镜像中的启动命令。

4、ENV

ENV 指令用来设置环境变量,格式有两种:

  • ENV <key> <value
  • ENV <key1>=<value1> <key2>=<value2>

环境变量在后面的其它指令中可以通过 $key 来使用:

FROM ubuntu
ENV VERSION="8-jre"

RUN apt-get update \
    && apt-get install -y openjdk-$VERSION
...

5、ARG

ARG 指令指定构建参数,与 ENV 效果一样,都是设置环境变量。不同的是,ARG 设置的构建参数,在容器运行时不存在。

格式:ARG <key>[=<默认值>],可以指定默认值,也可以不指定。

FROM alpine
ARG NAME="Hello, Docker!"

RUN echo $NAME
CMD echo $NAME

对于以上 Dockerfile,在构建时可以看到输出,但是在运行容器时没有输出。

ARG 设置的参数可以在构建命令中指定:docker build --build-arg <key>=<value>

6、VOLUME

VOLUME 指令用来定义匿名卷。

  • VOLUME <路径>
  • VOLUME ["路径1", "路径2", ...]

对于数据库类需要保持数据的应用,其文件应该保存于卷(volume)中,在 Dockerfile 中,可以事先将指定的目录挂载为匿名卷。

VOLUME /data

这里 /data 目录在容器运行时自动挂载为匿名卷,任何写入 /data 中的数据都不会记录到容器的存储层。在运行时可以覆盖这个挂载设置:

docker run -v dbdir:/data

以上命令将 dbdir 目录挂载到了 /data,替换了 Dockerfile 中的挂载配置。

7、EXPOSE

EXPOSE 指令指定容器运行时暴露的端口。格式:EXPOSE <端口1> [<端口2> ...]

FROM ubuntu
EXPOSE 8080

RUN apt-get update \
    && apt-get install -y tomcat8
...

以上 Dockerfile 安装了 tomcat 应用,在运行容器时会暴露 8080 端口。

EXPOSE 只是指定了容器暴露的端口,并不会在宿主机进行端口映射。在使用 docker run -P 时,会自动随机映射 EXPOSE 指定的端口,也可以使用 -p 指定端口:docker run -p <宿主端口>:<容器端口>

8、WORKDIR

WORKDIR 指令指定工作目录,即指定当前目录,类似于 cd 命令,以后各层的当前目录都是 WORKDIR 指定的目录。如果目录不存在,会自动创建。格式:WORKDIR <目录路径>

不能把 Dockerfile 当成 Shell 脚本来写:

RUN cd /src/app
RUN java -jar app.jar

以上操作中第二行的工作目录并不是 /src/app,两个指令不在同一层,第一个 RUN 指令的 cd 操作和第二个没有任何关系。因此要切换目录,应该使用 WORKDIR 来指定。

9、USER

USER 指令指定当前用户。与 WORKDIR 相似,会影响以后的层。USER 改变执行 RUNCMDENTRYPOINT 的用户。格式:USER <用户名>[:<用户组>]

USER 指定的用户和组必须是事先创建好的,否则无法切换。

# 添加用户
RUN groupadd -r redis \
    && useradd -r -g redis redis
USER redis
ENTRYPOINT ["reids-server"]

10、ONBUILD

ONBUILD 指令后面跟的是其它指令,它在当前镜像构建时不会被执行,只有以当前镜像为基础镜像去构建下一级镜像时才会被执行。格式:ONBUILD <其它指令>

FROM openjdk:8-jre-alpine
WORKDIR /app
ONBUILD COPY ./app.jar /app
...

这个 Dockerfile 在构建时不会执行 ONBUILD

FROM my-jre
...

假设之前构建的镜像名是 my-jre,以上 Dockerfile 构建镜像时,原来的 ONBUILD 将执行。

11、ENTRYPOINT

ENTRYPOINT 的格式与 CMD 一样有两种格式。

它和 CMD 一样都是指定容器启动的程序和参数,但稍有区别。当指定了 ENTRYPOINT 后,CMD 的内容将作为参数加到 ENTRYPOINT 后面。

也就是变成了:

<ENTRYPOINT> "<CMD>"

ENTRYPOINT 可以让镜像像命令一样使用,当仅仅使用 CMD 时,run 命令中镜像名后面的参数会替换 CMD 的内容。使用 ENTRYPOINT 后,这些参数将附加到原来命令的后面。

FROM alpine
ENTRYPOINT [ "ls" ]

使用以上 Dockerfile 构建的镜像运行容器:

docker run app -al

-al 参数将附加到 ENTRYPOINT 指定的命令后面,当容器启动时执行的是 ls -al

12、Dockerfile案例

FROM ubuntu:18.04    # 从仓库拉取一个Ubuntu 18.04的进项

WORKDIR /root		# 容器中的工作目录

RUN apt-get update && \
    apt-get install -y vim python3 python3-pip language-pack-zh* mysql-client	# 容器中安装环境

RUN python3 -m pip install -r /root/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/    # 容器中安装项目依赖


五、docker安装MySQL

1、下载指定版本镜像

docker pull mysql:8.0.21

2、启动容器

cd /home/up/docker_test		# 进入挂载文件

docker run -p 3307:3306 --name mysql-8 -v $PWD/mysql_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=hf1234 -d mysql:8.0.21			# $PWD 表示当前目录下
-p:表示端口映射,冒号左面的是宿主机的端口,而右侧则表示的是MySQL容器内的端口
--name:给MySQL容器取的名字
-d:表示后台运行
-e MYSQL_ROOT_PASSWORD:设置root用户密码
-v:表示挂载路径,冒号左面的表示宿主机的挂载目录,冒号右边则表示容器内部的路径。

3、进入容器

docker exec -it mysql-8 bash
msyql -uroot -p			# 登录数据库

可能出现的错误:

4、可设置远程访问

use mysql;

select host,user from user;

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '<root_password>';

flush privileges;

六、docker容器间通信

如果在同一个主机上,MySQL为一个容器,django项目为另一个容器,那么就需要两个容器能够互相访问

1、案例

django应用容器MySQL容器

cd /home/xx/docker_recoder	# 宿主机挂载目录
xx@xx: /home/xx/docker_recoder: $ docker run -d --name mysqlserver -v $PWD/mysql/mysql_data:/var/lib/mysql -p3307:3306 mysql:latest  # 运行MySQL容器

xx@xx: /home/xx/docker_recoder: $ docker run -d --name django-web -v $PWD/web/logs:/root/web/logs -p8001:8000 django_web:1.0  # 启动django应用容器,$PWD表示当前目录

注意事项

  • 在django中MySQL的host用MySQL容器内部的 ipport为容器内部的port(3306)

    • 可通过docker inspect mysqlserver查看容器信息,无需安装工具
    • 可通过进入容器后,ifconfig获取容器ip,但是需要安装ifconfig,如下第三点所示安装方法

  • 查看容器间能否通信,可以ping <container ip>,能ping通说明能通信

    ping 172.17.0.3
    
  • 如果无pingifconfig等工具

    # 安装ping
    apt-get install inetutils-ping
    
    # 安装ifconfig
    apt-get install net-tools
    

2、实现同主机容器间通信

在安装好docker后,docker将创建一个linux网桥docker0,它在内核层连通了其他的物理或虚拟网卡,也就是所有容器和本地主机都放到同一个物理网络。docker还会给我们创建三个网络:bridge/host/none网桥bridge模式是在实际项目中常用的,在没有指定相关网络的情况下,容器都会连接到默认的bridge网络。可以通过 --network 参数指定容器连接的网络。

docker network ls		# 查看宿主机中所有的docker网络

(1)link连接

默认的桥接网络支持使用端口映射和docker run --link命令,实现容器间互相通信。该方法已经在官方文档中标识为不推荐使用

(2)自定义bridge网络,实现容器间通信

从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过“容器名”通信。使用默认的bridge网络,不能通过DNS server实现通过容器名通信,但是使用自定义bridge网络可以做到通过容器名互相通信

0)使用默认的网桥,即启动容器时,不指定--network,此时可通过 ip进行ping,但是不能通过容器名进行ping

进入容器,查看hosts,此时hosts中并没有其他容器的信息

docker exec -it contian-name bash
cat /etc/hosts

1)创建网桥

docker network create --driver=bridge mybridge
docker network create \
  --driver=bridge \
  --subnet=172.28.5.0/24 \
  --ip-range=172.28.5.0/24 \
  --gateway=172.28.5.1 \
  mybridge

2)使用自定义网桥启动容器

通过--network指定网桥

docker run --name name --network mybridge -p 8001:8000 image_id

3)查看容器网桥

docker network inspect mybridge

如图,两个容器mysql-test、django-test都绑在了该网桥

3、容器加入网桥的方式

1)启动容器时,通过--network指定网桥

docker run --network

2)启动容器后,加入网桥

docker run  --name my-name    # 不指定网桥
docker network connect my_bridge my-name		 # 通过 docker network connect 为已启动的容器添加网桥

七、docker化部署流程

  1. docker pull mysql:8.0拉取MySQL的镜像

  2. 项目中编写Dockerfiledocker build -t image_name .制作项目镜像

  3. 创建网桥,docker network create --driver=bridge mybridge

  4. 启动容器

    docker run -d --name mysql-1 --network mybridge -e MYSQL_ROOT_PASSWORD=123123 -v /home/xx/mysql_data:/var/lib/mysql -p 3307:3306 mysql:8.0

    docker run --name django-test --network mybridge -p 8001:8000 django_test:latst

  5. 进入容器,可修改项目的配置,或者将配置文件通过-v挂载到宿主机

posted on 2020-08-05 15:40  凉城旧巷  阅读(892)  评论(0编辑  收藏  举报