Last week I wrote about my self-hosted Sentry install in 3 Docker containers. This week I want to bring you the rest of my self-hosted tools for developers, all rolled into a convenient docker-compose.yml.

Contents

Version Control (GitLab)

Code Analysis (SonarQube)

Email (exim4)

Code Search (Etsy Hound)

Visualization (Grafana)

User Error Monitoring (Sentry)

System Monitoring (Prometheus)

Log Monitoring (ELK (Elasticsearch, Logstash, and Kibana))

Docker Web GUI (Portainer)

All Services Rolled Up

About The Configurations Shown

The configuration files described and shown below are exactly what I’m running at this time, 2018-04-05, (with personal details removed, of course) and therefore they may need to be adjusted slightly to your own preferences. Specifically, you will likely have to change the volumes for all the containers. I have them set to the /srv/$SERVICE_NAME and /srv/configs/$SERVICE_NAME paths for bulk data and configuration files respectively. The idea is that I would be able to move my docker-compose and configs directory to a new computer and immediately have this same stack up and running. Some bulk data may be lost, but I don’t consider any of it critical. The docker-compose file is using version 3.

Version Control (GitLab)

One of the most important developer tools is a version control system. Most developers use Git and especially GitHub. These are of course great tools, but I also run my own GitLab server. As the name suggests, GitLab uses the same Git system as always, but it has some more powerful features, chief among which is CI/CD. GitLab has a fairly simple continuous integration/continuous deployment system built in. It utilizes a .gitlab-ci.yml file placed in your repository to define operations to perform. It uses a separate docker container running GitLab Runner to spawn additional containers that execute the tasks you define in the gitlab-ci file. In addition to CI/CD, since you’re running your own server you can have as many private repositories as you want and even share private repositories with selected contributors.

Compose

The docker-compose section for my GitLab setup is shown below. Some things to note are that the GitLab Runner may need some additional setup, especially getting a registration token. Here are GitLab’s instructions for the registration process.

GitLab Stack
GitLab Stack

gitlab:

image: 'gitlab/gitlab-ce:latest'

restart: always

container_name: gitlab

hostname: # YOUR HOSTNAME ex. git.example.com

links:

- smtp

environment:

GITLAB_OMNIBUS_CONFIG: |

external_url '# YOUR URL ex. https://git.example.com #';

gitlab_rails['gitlab_email_from'] = '# YOUR EMAIL ADDRESS #';

gitlab_rails['gitlab_email_reply_to'] = '# YOUR EMAIL ADDRESS #';

gitlab_rails['smtp_enable'] = 'true';

gitlab_rails['smtp_address'] = 'smtp';

ports:

- '180:80'

volumes:

- '/srv/configs/gitlab/gitlab:/etc/gitlab'

- '/srv/gitlab/logs:/var/log/gitlab'

- '/srv/gitlab/data:/var/opt/gitlab'

End GitLab
GitLab CI/CD Runner

gitlab-runner:

image: 'gitlab/gitlab-runner:latest'

restart: always

container_name: gitlab-runner

links:

- gitlab

environment:

- CI_SERVER_URL=http://gitlab/

- RUNNER_NAME=local-docker-runner

- REGISTER_NON_INTERACTIVE=true

- REGISTRATION_TOKEN=# YOUR REGISTRATION TOKEN FROM GITLAB #

- RUNNER_EXECUTOR=docker

- DOCKER_IMAGE=ubuntu:artful

- REGISTER_LOCKED=false

volumes:

- /srv/configs/gitlab/gitlab-runner:/etc/gitlab-runner

- /srv/gitlab-runner/home:/home/gitlab-runner

- /var/run/docker.sock:/var/run/docker.sock

End GitLab CI/CD Runner
End GitLab Stack

Code Analysis (SonarQube)

Code just working isn’t good enough, you ought to enforce some guidelines on code style to avoid potential problems. One tool to do this is SonarQube, which is a static analysis tool. This means that it simply looks at your source code and will run a multitude of different rulesets against it looking for issues. It has support for all the popular languages and you can customize the rules that it enforces.

Compose

To use SonarQube you will need a MySQL or other supported server (the configuration below shows MySQL/MariaDB). You can run MySQL in another container or perhaps on a separate database server. Fill in the configuration below with the database information, and that should be all the setup required.

Sonarqube Static Code Analysis

sonarqube:

container_name: sonarqube

image: 'sonarqube:latest'

restart: always

links:

- smtp

ports:

- 780:9000

environment:

- SONARQUBE_JDBC_URL=jdbc:mysql://# MYSQL HOST #:3306/# MYSQL DATABASE #?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance

- SONARQUBE_JDBC_USERNAME=# MYSQL USERNAME #

- SONARQUBE_JDBC_PASSWORD=# MYSQL PASSWORD #

volumes:

- /srv/sonarqube/conf:/opt/sonarqube/conf

- /srv/sonarqube/data:/opt/sonarqube/data

- /srv/sonarqube/extensions:/opt/sonarqube/extensions

- /srv/sonarqube/bundled-plugins:/opt/sonarqube/lib/bundled-plugins/opt/sonarqube/lib/bundled-plugins

End Sonarqube Static Code Analysis

Email (exim4)

Many of the containers described in this article can take advantage of emails to alert you of issues if you set them up. A really simple way to do this if you don’t have your own mail server is to just use your existing GMail account.

Compose

SMTP Email

smtp:

image: 'tianon/exim4:latest'

restart: always

environment:

GMAIL_USER: # YOUR GMAIL USERNAME #

GMAIL_PASSWORD: # YOUR GMAIL PASSWORD #

End SMTP Email

Code Search (Etsy Hound)

Occasionally you may find that you’re writing something that you know you’ve done before, but you just can’t seem to find what project or file its in. Hound is a very simple code search tool that indexes your repositories and allows you to search them using regular expressions. Hound requires a bit of configuration in config.json which you can learn about here.

Compose

Hound Code Search

hound:

container_name: hound

image: 'etsy/hound:latest'

restart: always

ports:

- 580:6080

volumes:

- /srv/configs/hound/config.json:/data/config.json

- /srv/hound/data:/data/data

End Hound Code Search

Example Hound Configuration

Here is an example configuration for Hound, just put in your GitHub URLs and project names.

{

"max-concurrent-indexers" : 5,

"dbpath" : "data",

"repos" : {

"graphPlayground" : {

"url" : "https://github.com/MikeDombo/graphPlayground.git",

"enable-push-updates" : true

}

}

}

Visualization (Grafana)

If any of your projects are generating some statistics or writing into a database, then maybe you’d like a simple dashboard to visualize them. Grafana is the best way to do this without writing it yourself. It allows you to hookup many different datasources including MySQL, Graphite, Prometheus, and more and then show data in appealing graphs, tables, etc. Grafana comes with some dashboards and there are more community generated dashboards on their site. Most of the configuration you’ll do with Grafana is to setup a dashboard the way you like it.

Compose

Grafana Dashboard

grafana:

container_name: grafana

image: 'grafana/grafana:latest'

restart: always

links:

- smtp

ports:

- 680:3000

environment:

- GF_SERVER_ENABLE_GZIP=true

- GF_SERVER_ROOT_URL=%(protocol)s://%(domain)s/

- GF_SERVER_DOMAIN=# DOMAIN ex. graphs.example.com #

- GF_SMTP_ENABLED=true

- GF_SMTP_HOST=smtp

- GF_AUTH_ORG_NAME=anon_org

- GF_AUTH_ANONYMOUS_ENABLED=true

volumes:

- /srv/configs/grafana:/var/lib/grafana

End Grafana Dashboard

User Error Monitoring (Sentry)

See my post from last week to configure a self-hosted Sentry to collect errors that users encounter while using your applications.

System Monitoring (Prometheus)

Prometheus is one of several popular time-series databases. I use it to collect load, network, and other statistics from servers and Docker containers. I have it configured using Google CAdvisor and Prometheus’s node-exporter to gather stats on containers and hosts respectively. I then use Grafana to visualize the data from Prometheus.

Compose

Prometheus Monitoring Stack

prometheus:

container_name: prometheus

image: 'prom/prometheus:latest'

restart: always

links:

- grafana

- cadvisor

- node-exporter

command:

- '--config.file=/etc/prometheus/prometheus.yml'

- '--storage.tsdb.path=/prometheus'

- '--web.console.libraries=/usr/share/prometheus/console_libraries'

- '--web.console.templates=/usr/share/prometheus/consoles'

volumes:

- /srv/configs/prometheus:/etc/prometheus

- /srv/prometheus:/prometheus

Monitoring for this host

node-exporter:

image: prom/node-exporter

container_name: prometheus_node-exporter

volumes:

- /proc:/host/proc:ro

- /sys:/host/sys:ro

- /:/rootfs:ro

command:

- '--path.procfs=/host/proc'

- '--path.sysfs=/host/sys'

- --collector.filesystem.ignored-mount-points

- "^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($|/)"

restart: always

Docker container monitoring

cadvisor:

image: google/cadvisor

restart: always

volumes:

- /:/rootfs:ro

- /var/run:/var/run:rw

- /sys:/sys:ro

- /var/lib/docker/:/var/lib/docker:ro

End Prometheus Monitoring Stack

Prometheus Configuration

Here as the Prometheus configuration that I used prometheus.yml to get node-exporter and cadvisor data into my Prometheus. Put it in /srv/configs/prometheus/prometheus.yml if you’re using my docker-compose file from above.

my global config

global:

scrape_interval: 15s # By default, scrape targets every 15 seconds.

evaluation_interval: 15s # By default, scrape targets every 15 seconds.

scrape_timeout is set to the global default (10s).

A scrape configuration containing exactly one endpoint to scrape:

Here it's Prometheus itself.

scrape_configs:

The job name is added as a label job=<job_name> to any timeseries scraped from this config.

  • job_name: 'prometheus'

    Override the global default and scrape targets from this job every 5 seconds.

    scrape_interval: 5s

    static_configs:

    • targets: ['localhost:9090']
  • job_name: 'node-exporter'

    Override the global default and scrape targets from this job every 5 seconds.

    scrape_interval: 5s

    static_configs:

    • targets: ['node-exporter:9100']
  • job_name: 'cadvisor'

    Override the global default and scrape targets from this job every 5 seconds.

    scrape_interval: 5s

    static_configs:

    • targets: ['cadvisor:8080']

      Log Monitoring (ELK (Elasticsearch, Logstash, and Kibana))

      To store and search through logs including Apache access and error logs and Linux system logs I use the ELK stack from Elastic.co.

      For configuration, you’ll have to setup Filebeat or some other way to get logs from your server and into ELK.

Compose

ELK Stack

elasticsearch:

image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.3.0

container_name: elasticsearch

restart: always

volumes:

- /srv/configs/elk/elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro

- /srv/elk/elasticsearch/data:/usr/share/elasticsearch/data

ports:

- "9200:9200"

- "9300:9300"

environment:

ES_JAVA_OPTS: "-Xmx256m -Xms256m"

networks:

- elk

logstash:

image: docker.elastic.co/logstash/logstash-oss:6.3.0

container_name: logstash

restart: always

volumes:

- /srv/configs/elk/logstash/config:/usr/share/logstash/config:ro

- /srv/configs/elk/logstash/pipeline:/usr/share/logstash/pipeline:ro

ports:

- "5000:5000"

environment:

LS_JAVA_OPTS: "-Xmx256m -Xms256m"

networks:

- elk

depends_on:

- elasticsearch

kibana:

image: docker.elastic.co/kibana/kibana-oss:6.3.0

container_name: kibana

restart: always

volumes:

- /srv/configs/elk/kibana/:/usr/share/kibana/config:ro

ports:

- "5601:5601"

networks:

- elk

depends_on:

- elasticsearch

End ELK Stack

networks:

ELK Stack Network

elk:

driver: bridge

End ELK Stack Network

Configuration

I use the default ElasticSearch and Logstash configuration, and the following for Kibana. I also am including here a pipeline/logstash.conf which has rules for Apache access and error, PHP error, and Syslogs.

Kibana.yml

server.name: kibana

server.host: "0.0.0.0"

elasticsearch.url: http://elasticsearch:9200

pipeline/logstash.conf

input {

beats {

port => 5000

ssl => false

}

}

PHP

filter {

if "php_error" in [tags] {

grok {

match => { "message" => "^[(?%{MONTHDAY}-%{MONTH}-%{YEAR} %{TIME} (%{TZ}|(\w+/\w+)))] ?%{GREEDYDATA:message}" }

overwrite => [ "message" ]

}

date {
match => [ "logtime", "d-MMM-yyyy HH:mm:ss ZZZ" ]
remove_field => [ "logtime" ]
}

}

}

Apache Access and Error

filter {

if "apache_access" in [tags] {

grok {

match => [

"message" , "%{COMBINEDAPACHELOG}+%{GREEDYDATA:extra_fields}",

"message" , "%{COMMONAPACHELOG}+%{GREEDYDATA:extra_fields}"

]

overwrite => [ "message" ]

}

mutate {

convert => ["response", "integer"]

convert => ["bytes", "integer"]

convert => ["responsetime", "float"]

}

geoip {

source => "clientip"

target => "geoip"

add_tag => [ "apache-geoip" ]

}

date {

match => [ "timestamp" , "dd/MMM/YYYY:HH:mm:ss Z" ]

remove_field => [ "timestamp" ]

}

useragent {

source => "agent"

}

}

if "apache_error" in [tags] {

grok {

match => [ "message", "%{HTTPD_ERRORLOG}" ]

overwrite => ["message"]

}

if !("_grokparsefailure" in [tags]) {
geoip {
source => "clientip"
}
}

}

}

Syslog

filter {

if "syslog" in [tags] {

grok {

match => [ "message", "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:[%{POSINT:syslog_pid}])?: %{GREEDYDATA:message}" ]

overwrite => ["message"]

}

date {

match => [ "syslog_timestamp", "MMM d HH:mm:ss", "MMM dd HH:mm:ss" ]

timezone => "America/New_York"

}

}

}

Removing annoying tag

filter {

if "beats_input_codec_plain_applied" in [tags] {

mutate {

remove_tag => ["beats_input_codec_plain_applied"]

}

}

}

Output

output {

elasticsearch {

hosts => "elasticsearch:9200"

sniffing => true

manage_template => false

document_type => "%{[@metadata][type]}"

}

}

Docker Web GUI (Portainer)

The simplest of all configurations, Portainer is a web app that enables you to manage your Docker containers.

Compose

Portainer Docker Web GUI

portainer:

container_name: portainer

image: 'portainer/portainer:latest'

restart: always

ports:

- '480:9000'

volumes:

- /var/run/docker.sock:/var/run/docker.sock

- /srv/configs/portainer:/data

End Portainer Docker Web GUI

All Rolled Up

For your convenience, here’s the whole docker-compose that I described in parts above. Many of the containers won’t run as-is, instead they’ll require a bit more configuration.

Compose
version: '3' services:
##### GitLab Stack #####
##### GitLab Stack #####
gitlab:
image: 'gitlab/gitlab-ce:latest'
restart: always
container_name: gitlab
hostname: # YOUR HOSTNAME ex. git.example.com
links:
- smtp
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url '# YOUR URL ex. https://git.example.com #';
gitlab_rails['gitlab_email_from'] = '# YOUR EMAIL ADDRESS #';
gitlab_rails['gitlab_email_reply_to'] = '# YOUR EMAIL ADDRESS #';
gitlab_rails['smtp_enable'] = 'true';
gitlab_rails['smtp_address'] = 'smtp';
ports:
- '180:80'
volumes:
- '/srv/configs/gitlab/gitlab:/etc/gitlab'
- '/srv/gitlab/logs:/var/log/gitlab'
- '/srv/gitlab/data:/var/opt/gitlab'
##### End GitLab #####
##### GitLab CI/CD Runner #####
gitlab-runner:
image: 'gitlab/gitlab-runner:latest'
restart: always
container_name: gitlab-runner
links:
- gitlab
environment:
- CI_SERVER_URL=http://gitlab/
- RUNNER_NAME=local-docker-runner
- REGISTER_NON_INTERACTIVE=true
- REGISTRATION_TOKEN=# YOUR REGISTRATION TOKEN FROM GITLAB #
- RUNNER_EXECUTOR=docker
- DOCKER_IMAGE=ubuntu:artful
- REGISTER_LOCKED=false
volumes:
- /srv/configs/gitlab/gitlab-runner:/etc/gitlab-runner
- /srv/gitlab-runner/home:/home/gitlab-runner
- /var/run/docker.sock:/var/run/docker.sock
##### End GitLab CI/CD Runner #####
##### End GitLab Stack ##### ##### Sonarqube Static Code Analysis #####
sonarqube:
container_name: sonarqube
image: 'sonarqube:latest'
restart: always
links:
- smtp
ports:
- 780:9000
environment:
- SONARQUBE_JDBC_URL=jdbc:mysql://# MYSQL HOST #:3306/# MYSQL DATABASE #?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance
- SONARQUBE_JDBC_USERNAME=# MYSQL USERNAME #
- SONARQUBE_JDBC_PASSWORD=# MYSQL PASSWORD #
volumes:
- /srv/sonarqube/conf:/opt/sonarqube/conf
- /srv/sonarqube/data:/opt/sonarqube/data
- /srv/sonarqube/extensions:/opt/sonarqube/extensions
- /srv/sonarqube/bundled-plugins:/opt/sonarqube/lib/bundled-plugins/opt/sonarqube/lib/bundled-plugins
##### End Sonarqube Static Code Analysis ##### ##### SMTP Email #####
smtp:
image: 'tianon/exim4:latest'
restart: always
environment:
GMAIL_USER: # YOUR GMAIL USERNAME #
GMAIL_PASSWORD: # YOUR GMAIL PASSWORD #
##### End SMTP Email ##### ##### Hound Code Search #####
hound:
container_name: hound
image: 'etsy/hound:latest'
restart: always
ports:
- 580:6080
volumes:
- /srv/configs/hound/config.json:/data/config.json
- /srv/hound/data:/data/data
##### End Hound Code Search ##### ##### Grafana Dashboard #####
grafana:
container_name: grafana
image: 'grafana/grafana:latest'
restart: always
links:
- smtp
ports:
- 680:3000
environment:
- GF_SERVER_ENABLE_GZIP=true
- GF_SERVER_ROOT_URL=%(protocol)s://%(domain)s/
- GF_SERVER_DOMAIN=# DOMAIN ex. graphs.example.com #
- GF_SMTP_ENABLED=true
- GF_SMTP_HOST=smtp
- GF_AUTH_ORG_NAME=anon_org
- GF_AUTH_ANONYMOUS_ENABLED=true
volumes:
- /srv/configs/grafana:/var/lib/grafana
##### End Grafana Dashboard ##### ##### Sentry Stack #####
sentry-base:
image: 'sentry:latest'
container_name: sentry-base
restart: always
depends_on:
- sentry-redis
- sentry-postgres
links:
- sentry-redis
- sentry-postgres
ports:
- 880:9000
env_file:
- sentry.env
volumes:
- /srv/configs/sentry/sentry:/var/lib/sentry/files
sentry-cron:
image: 'sentry:latest'
container_name: sentry-cron
restart: always
depends_on:
- sentry-redis
- sentry-postgres
links:
- sentry-redis
- sentry-postgres
command: "sentry run cron"
env_file:
- sentry.env
volumes:
- /srv/configs/sentry/sentry:/var/lib/sentry/files
sentry-worker:
image: 'sentry:latest'
container_name: sentry-worker
restart: always
depends_on:
- sentry-redis
- sentry-postgres
links:
- sentry-redis
- sentry-postgres
command: "sentry run worker"
env_file:
- sentry.env
volumes:
- /srv/configs/sentry/sentry:/var/lib/sentry/files
sentry-redis:
image: 'redis:alpine'
container_name: sentry-redis
restart: always
sentry-postgres:
image: 'postgres:latest'
container_name: sentry-postgres
restart: always
environment:
POSTGRES_USER: sentry
POSTGRES_PASSWORD: sentry
POSTGRES_DB: sentry
volumes:
- /srv/configs/sentry/postgres:/var/lib/postgresql/data
##### End Sentry Stack ##### ##### Prometheus Monitoring Stack #####
prometheus:
container_name: prometheus
image: 'prom/prometheus:latest'
restart: always
links:
- grafana
- cadvisor
- node-exporter
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
volumes:
- /srv/configs/prometheus:/etc/prometheus
- /srv/prometheus:/prometheus
# Monitoring for this host #
node-exporter:
image: prom/node-exporter
container_name: prometheus_node-exporter
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- --collector.filesystem.ignored-mount-points
- "^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($|/)"
restart: always
# Docker container monitoring #
cadvisor:
image: google/cadvisor
restart: always
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
##### End Prometheus Monitoring Stack ##### ##### ELK Stack #####
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.3.0
container_name: elasticsearch
restart: always
volumes:
- /srv/configs/elk/elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
- /srv/elk/elasticsearch/data:/usr/share/elasticsearch/data
ports:
- "9200:9200"
- "9300:9300"
environment:
ES_JAVA_OPTS: "-Xmx256m -Xms256m"
networks:
- elk
logstash:
image: docker.elastic.co/logstash/logstash-oss:6.3.0
container_name: logstash
restart: always
volumes:
- /srv/configs/elk/logstash/config:/usr/share/logstash/config:ro
- /srv/configs/elk/logstash/pipeline:/usr/share/logstash/pipeline:ro
ports:
- "5000:5000"
environment:
LS_JAVA_OPTS: "-Xmx256m -Xms256m"
networks:
- elk
depends_on:
- elasticsearch
kibana:
image: docker.elastic.co/kibana/kibana-oss:6.3.0
container_name: kibana
restart: always
volumes:
- /srv/configs/elk/kibana/:/usr/share/kibana/config:ro
ports:
- "5601:5601"
networks:
- elk
depends_on:
- elasticsearch
##### End ELK Stack ##### ##### Portainer Docker Web GUI #####
portainer:
container_name: portainer
image: 'portainer/portainer:latest'
restart: always
ports:
- '480:9000'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /srv/configs/portainer:/data
##### End Portainer Docker Web GUI ##### networks:
##### ELK Stack Network #####
elk:
driver: bridge
##### End ELK Stack Network #####

from https://mikedombrowski.com/2018/04/docker-compose-setup-for-self-hosting-development-tools/

Docker-compose Setup for Self-hosting Development & Deployment Tools的更多相关文章

  1. Docker Compose 之进阶篇

    笔者在前文<Docker Compose 简介>和<Dcoker Compose 原理>两篇文章中分别介绍了 docker compose 的基本概念以及实现原理.本文我们将继 ...

  2. 使用docker compose编排容器

    一.安装docker compose 二进制包安装 1.安装 Docker Compose 从 官方 GitHub Release 处直接下载编译好的二进制文件即可 # curl -L https:/ ...

  3. kubernetes 实战6_命令_Share Process Namespace between Containers in a Pod&Translate a Docker Compose File to Kubernetes Resources

    Share Process Namespace between Containers in a Pod how to configure process namespace sharing for a ...

  4. [Docker] Converting from Docker Compose to Kubernetes

    kompose is a tool to help users who are familiar with docker-compose move to Kubernetes. kompose tak ...

  5. Docker Compose—简化复杂容器应用的利器

    Compose是用于定义和运行复杂Docker应用的工具.你可以在一个文件中定义一个多容器的应用,然后使用一条命令来启动你的应用,然后所有相关的操作都会被自动完成. 1. 安装Docker和Compo ...

  6. .NET遇上Docker - 使用Docker Compose组织Ngnix和.NETCore运行

    本文工具准备: Docker for Windows Visual Studio 2015 与 Visual Studio Tools for Docker 或 Visual Studio 2017 ...

  7. Docker学习笔记 - Docker Compose 脚本命令

    Docker Compose 配置文件包含 version.services.networks 三大部分,最关键的是 services 和 networks 两个部分, version: '2' se ...

  8. Docker入门(三)使用Docker Compose

    Compose介绍   Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排.Compose 是一个用户定义和运行多个容器的 Docker 应用程序.在 ...

  9. Docker Compose 原理

    Docker 的优势非常明显,尤其是对于开发者来说,它提供了一种全新的软件发布机制.也就是说使用 docker 镜像作为软件产品的载体,使用 docker 容器提供独立的软件运行上下文环境,使用 do ...

随机推荐

  1. [adb]查看 App的appPackage和appActivity

    最近在写app的UI框架,写脚本之前需要知道app的包名和activity,如果获取呢: 需求配置abdrioid sdk环境 方法1:abd log 1. 打开cmd命令窗口2.在命令窗口中输入,a ...

  2. ActionChains定位元素

    ActionChains UI自动化测试过程中,经常遇到那种,需要鼠标悬浮后,要操作的才会元素出现的这种场景,那么我们就要模拟鼠标悬浮到某一个位置,做一系列的连贯操作,Selenium给我们提供了Ac ...

  3. 51nod1046 A^B Mod C【快速幂】

    给出3个正整数A B C,求A^B Mod C. 例如,3 5 8,3^5 Mod 8 = 3. Input 3个正整数A B C,中间用空格分隔.(1 <= A,B,C <= 10^9) ...

  4. java IO框架分析

    jave.io框架 2010-11-10 22:18:34|  分类: 默认分类|举报|字号 订阅     可从IO的类层次,IO框架的设计模式来论述. 总体来说,IO可以分为字节流和字符流,不同在于 ...

  5. css sprites拼合

    一.什么是css sprites css sprites直译过来就是CSS精灵.通常被解释为“CSS图像拼合”或“CSS贴图定位”.就是把网页中一些背景图片整合拼合成一张图片中,再利用DIV CSS的 ...

  6. HDU - 4323 - Magic Number

    先上题目: Magic Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  7. POJ 2068

    就是必胜点与必败点的计算而已.计算每一种情况.设st[i][j]为在第i个人剩下j个石头时的情况,拿它转移后的情况比较.可以到达必败点,则当前为必胜点.若只能到达必胜点,则当前点为必败点. #incl ...

  8. error at ::0 can't find referenced pointcut...解决方法

    error at ::0 can't find referenced pointcut...解决方法 学习了:http://dyldragon.iteye.com/blog/512612 升级aspe ...

  9. 命令行使用Eclipse的debug签名失败“找不到 xx.keystore证书链”

    1.debug签名位置 2.查看debug.keystore具体信息 3.使用命令行签名 注意:debug签名password为android 4.出错原因是签名的别名写错,应为androiddebu ...

  10. 支持中文的基于词为基本粒度的前缀树(prefix trie)python实现

    Trie树,也叫字典树.前缀树.可用于"predictive text"和"autocompletion".亦可用于统计词频(边插入Trie树边更新或加入词频) ...