docker-compose安装和初体验

compose介绍

在Docker中,我们从代码到部署容器需要经过两个步骤:

打包镜像docker build;
部署启动容器docker run;

在真实的企业级应用中,一个服务往往需要和很多个其它的服务进行关联,单个服务也有可能有多个容器实例,如果需要发布,很可能会需要人员手动对每一个容器进行打包和启动的操作,非常繁琐,容易出错。在这种背景下,Docker Compose就有了用武之地。简单来说,Docker Compose是一个用于定义和运行多个容器的工具,通过docker-compose.yml来实现对容器集群的编排工作。

Docker Compose管理如下三个内容:

1、工程,docker-compose运行的目录即为一个工程,在微服务场景下,我们往往都是使用git submodule的方式组建工程的,因此父项目就可以成为一个docker compose的工程;
2、服务,对应子项目,一个工程可以包含多个子项目;
3、容器,对应服务的实例,一个服务可以有多个实例;

Docker Compose当然也存在不足的地方,就是它只能用在单一host上进行容器编排,无法跨节点host对容器进行编排,那是Docker Swarm和K8s的范畴了,后续再讨论。

compose安装

下载地址

sudo curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
或
sudo curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

 增加文件可执行权限

sudo chmod +x /usr/local/bin/docker-compose

查看安装状态

[root@localhost ~]# docker-compose --version
docker-compose version 1.25.1, build a82fef07

compose命令介绍

[root@localhost ~]# docker-compose --help
Define and run multi-container applications with Docker.

Usage:
  docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
  docker-compose -h|--help

Options:
  -f, --file FILE             Specify an alternate compose file
                              (default: docker-compose.yml)
  -p, --project-name NAME     Specify an alternate project name
                              (default: directory name)
  --verbose                   Show more output
  --log-level LEVEL           Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
  --no-ansi                   Do not print ANSI control characters
  -v, --version               Print version and exit
  -H, --host HOST             Daemon socket to connect to

  --tls                       Use TLS; implied by --tlsverify
  --tlscacert CA_PATH         Trust certs signed only by this CA
  --tlscert CLIENT_CERT_PATH  Path to TLS certificate file
  --tlskey TLS_KEY_PATH       Path to TLS key file
  --tlsverify                 Use TLS and verify the remote
  --skip-hostname-check       Don't check the daemon's hostname against the
                              name specified in the client certificate
  --project-directory PATH    Specify an alternate working directory
                              (default: the path of the Compose file)
  --compatibility             If set, Compose will attempt to convert keys
                              in v3 files to their non-Swarm equivalent
  --env-file PATH             Specify an alternate environment file

Commands:
  build              Build or rebuild services
  bundle             Generate a Docker bundle from the Compose file
  config             Validate and view the Compose file
  create             Create services
  down               Stop and remove containers, networks, images, and volumes
  events             Receive real time events from containers
  exec               Execute a command in a running container
  help               Get help on a command
  images             List images
  kill               Kill containers
  logs               View output from containers
  pause              Pause services
  port               Print the public port for a port binding
  ps                 List containers
  pull               Pull service images
  push               Push service images
  restart            Restart services
  rm                 Remove stopped containers
  run                Run a one-off command
  scale              Set number of containers for a service
  start              Start services
  stop               Stop services
  top                Display the running processes
  unpause            Unpause services
  up                 Create and start containers
  version            Show the Docker-Compose version information

docker-compose.yml 详解

YAML模板文件语法

默认的模板文件是docker-compose.yml,其中定义的每个服务都必须通过image指令指定镜像或build指令(需要Dockerfile)来自动构建。

其他大部分都跟docker run 中类似。 如果使用build指令,在Dockerfile中设置的选项(例如:CMD,EXPOSE,VOLUME,ENV等)将自动被获取,无需在docker-compose.yml中再次被设置。

1、image

指定为镜像名称或镜像ID。如果镜像不存在,Compose将尝试从互联网拉取这个镜像,例如: image: ubuntu image: orchardup/postgresql image: a4bc65fd

2、build

指定Dockerfile所在文件夹的路径。Compose将会利用他自动构建这个镜像,然后使用这个镜像。 build: ./dir

3、command

覆盖容器启动后默认执行的命令。 command: bundle exec thin -p 3000

 4、links

链接到其他服务容器,使用服务名称(同时作为别名)或服务别名(SERVICE:ALIAS)都可以。
links:
 - db
 - db:database
 - redis
注意:使用别名会自动在服务器中的/etc/hosts 里创建,如:172.17.2.186 db,相应的环境变量也会被创建。

 5、external_links

链接到docker-compose.yml外部的容器,甚至并非是Compose管理的容器。参数格式和links类似。 external_links:
- redis_1
 - project_db_1:mysql
 - project_db_2:sqlserver

 6、ports

暴露端口信息。 宿主机器端口:容器端口(HOST:CONTAINER)格式或者仅仅指定容器的端口(宿主机器将会随机分配端口)都可以。
ports:
 - "3306"
 - "8080:80"
 - "127.0.0.1:8090:8001"
注意:当使用 HOST:CONTAINER 格式来映射端口时,如果你使用的容器端口小于 60 你可能会得到错误得结果,因为 YAML 将会解析 xx:yy 这种数字格式为 60 进制。所以建议采用字符串格式。

 7、expose

暴露端口,与posts不同的是expose只可以暴露端口而不能映射到主机,只供外部服务连接使用;仅可以指定内部端口为参数。
expose:
 - "3000"
 - "8000"

 8、volumes

设置卷挂载的路径。可以设置宿主机路径:容器路径(host:container)或加上访问模式(host:container:ro)ro就是readonly的意思,只读模式。
volumes:
 - /var/lib/mysql:/var/lib/mysql
 - /configs/mysql:/etc/configs/:ro

 9、volunes_from

挂载另一个服务或容器的所有数据卷。
volumes_from:
 - service_name
 - container_name

 10、environment

设置环境变量。可以属于数组或字典两种格式。 如果只给定变量的名称则会自动加载它在Compose主机上的值,可以用来防止泄露不必要的数据。
environment:
 - RACK_ENV=development
 - SESSION_SECRET

 11、env_file

从文件中获取环境变量,可以为单独的文件路径或列表。 如果通过docker-compose -f FILE指定了模板文件,则env_file中路径会基于模板文件路径。 如果有变量名称与environment指令冲突,则以后者为准。

env_file: .env
env_file:
 - ./common.env
 - ./apps/web.env
 - /opt/secrets.env

环境变量文件中每一行都必须有注释,支持#开头的注释行。
# common.env: Set Rails/Rack environment
RACK_ENV=development

 12、extends

基于已有的服务进行服务扩展。例如我们已经有了一个webapp服务,模板文件为common.yml.

# common.yml
webapp:
build: ./webapp
environment:
\ - DEBUG=false
\ - SEND_EMAILS=false

编写一个新的 development.yml 文件,使用 common.yml 中的 webapp 服务进行扩展。 development.yml
web:
extends:
file: common.yml
service: 
  webapp:
    ports:
      \ - "8080:80"
    links:
      \ - db
    envelopment:
      - DEBUG=true
   db:
    image: mysql:5.7
后者会自动继承common.yml中的webapp服务及相关的环境变量。

 13、net

设置网络模式。使用和docker client 的 --net 参数一样的值。
# 容器默认连接的网络,是所有Docker安装时都默认安装的docker0网络.
net: "bridge"
# 容器定制的网络栈.
net: "none"
# 使用另一个容器的网络配置
net: "container:[name or id]"
# 在宿主网络栈上添加一个容器,容器中的网络配置会与宿主的一样
net: "host"

Docker会为每个节点自动创建三个网络: 网络名称 作用 bridge 容器默认连接的网络,是所有Docker安装时都默认安装的docker0网络 none 容器定制的网络栈 host 在宿主网络栈上添加一个容器,容器中的网络配置会与宿主的一样 附录: 操作名称 命令 创建网络 docker network create -d bridge mynet 查看网络列表 docker network ls

 14、pid

和宿主机系统共享进程命名空间,打开该选项的容器可以相互通过进程id来访问和操作。
pid: "host"

 docker-compose.yml实例

version: "2"

services:
### console
    console:
        build:
            context: ./images/console
            args:
                # console 容器 www-data用户密码
                - USERPASS=root
                - GIT_NAME=yangnan
                - GIT_EMAIL=20706149@qq.com
                - INSTALL_YARN=false
        volumes_from:
            - php-fpm
            - nginx
            - mysql
            - redis
        volumes:
            - ./ssh:/home/www-data/.ssh
        links:
            - redis
            - mysql
        tty: true

### php-fpm
    php-fpm:
        build: ./images/php-fpm
        volumes:
            - ./app/:/var/www/

### nginx
    nginx:
        image: nginx
        ports:
            - "8081:80"
        volumes_from:
            - php-fpm
        volumes:
            - ./logs/nginx/:/var/log/nginx/
            - ./images/nginx/sites:/etc/nginx/conf.d/
        links:
            - php-fpm

### mysql
    mysql:
        image: mysql
        ports:
            - "7706:3306"
        environment:
            MYSQL_ROOT_PASSWORD: "123"
            MYSQL_DATABASE: "test"
            MYSQL_USER: "root"
            MYSQL_PASSWORD: "123"
        volumes:
            - ./data/mysql:/var/lib/mysql

### redis
    redis:
        image: redis
        ports:
            - "6379:6379"
        volumes:
            - ./data/redis:/data

注意事项: 使用compose对Docker容器进行编排管理时,需要编写docker-compose.yml文件,初次编写时,容易遇到一些比较低级的问题,导致执行docker-compose up时先解析yml文件的错误。比较常见的是yml对缩进的严格要求。

yml文件还行后的缩进,不允许使用tab键字符,只能使用空格,而空格的数量也有要求,经过实际测试,发现每一行增加一个空格用于缩进是正常的。 比如:
web:
&lt;空格&gt;build:
&lt;空格&gt;&lt;空格&gt;command:
...
否则,很容易引起各种 yaml.scanner.ScannerError:的错误提示。

compose使用

单服务单容器使用

 1、新建一个SpringBoot应用,仅仅包含一个Controller:

package com.example.demo.lcfc;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import org.springframework.beans.factory.annotation.Autowired;

@RestController
public class HelloController {

    @GetMapping("/getHello")
    public String getHello(){
        return "myapp is running ok!!!";
    }
    
}

请务必保证程序能正常运行,并进行package,打成jar包。 

编写Dockerfile:

[root@localhost docker-compose]# cat Dockerfile 
FROM openjdk:8
EXPOSE 8080
ADD  target/demo-0.0.1-SNAPSHOT.jar /demo.jar
ENTRYPOINT ["java", "-jar", "demo.jar"]

 编写docker-compose.yml文件:

[root@localhost docker-compose]# cat docker-compose.yml 
# 使用的yml版本
version: "3.3"
services:
  # 服务名称,可以自定义
  myapp:
    # 容器名称,可以自定义
    container_name: myapp
    # 指定Dockerfile所在的目录
    build: .
    ports:
      - "8080:8080"

运行 docker-compose

docker-compose up -d

主要完成以下的两步操作:
镜像构建docker build;
启动yml中的所有容器docker run;

多服务多容器依赖使用

假设我们的应用需要依赖其它服务,比如需要使用redis,mysql等,那么这种场景下,就需要被依赖的容器先启动。

首先,我们改造上述例子中的myapp代码,需要引入redis的支持依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>       
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

redis配置 

package com.example.demo.lcfc;


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setConnectionFactory(factory);
//key序列化方式
        template.setKeySerializer(redisSerializer);
//value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

  Controller

package com.example.demo.lcfc;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import org.springframework.beans.factory.annotation.Autowired;

@RestController
public class HelloController {

    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/getHello")
    public String getHello(){
        Long counter = redisTemplate.opsForValue().increment("counter");
        return "myapp is running " + counter + "times!";
    }

}

重新打包上传,并修改docker-compose.yml

[root@localhost docker-compose]# cat docker-compose.yml 
# 使用的yml版本
version: "3.3"
services:
  # 服务名称,可以自定义
  myapp:
    # 容器名称,可以自定义
    # container_name: myapp
    # 指定Dockerfile所在的目录
    build: .
    ports:
      - "8080"
  myredis:
    image: "redis:latest"
    ports:
      - "6379:6379"

启动

docker-compose up -d 

 参考文章

docker-compose.yml 语法说明芝麻教程 (web3.xin)http://www.web3.xin/index/article/182.htmlhttps://www.jianshu.com/p/ee2fea4136f0https://www.jianshu.com/p/ee2fea4136f0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值