Merge branch 'master' into dev

This commit is contained in:
Tan Jiang 2017-01-24 12:16:53 +08:00
commit 27802f7620
38 changed files with 1462 additions and 263 deletions

View File

@ -1,5 +1,5 @@
If you are reporting a problem, please make sure the following information are provided: If you are reporting a problem, please make sure the following information are provided:
1)Version of docker engine and docker-compose 1)Version of docker engine and docker-compose.
2)Config files of harbor, you can get them by packaging "Deploy/config" directory 2)Config files of harbor, you can get them by packaging "harbor.cfg" and files in the same directory, including subdirectory.
3)Log files, you can get them by package the /var/log/harbor/ 3)Log files, you can get them by package the /var/log/harbor/ .

View File

@ -33,6 +33,7 @@ Refer to **[User Guide](docs/user_guide.md)** for more details on how to use Har
**Slack:** Join Harbor's community here: [VMware {code}](https://code.vmware.com/join/), Channel: #harbor. **Slack:** Join Harbor's community here: [VMware {code}](https://code.vmware.com/join/), Channel: #harbor.
**Email:** harbor@ vmware.com . **Email:** harbor@ vmware.com .
**WeChat Group:** Add WeChat id *connect1688* to join WeChat discussion group. **WeChat Group:** Add WeChat id *connect1688* to join WeChat discussion group.
More info on [partners and users](partners.md).
### Contribution ### Contribution
We welcome contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a pull request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). Contact us for any questions: harbor @vmware.com . We welcome contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a pull request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq). Contact us for any questions: harbor @vmware.com .
@ -46,13 +47,3 @@ This project uses open source components which have additional licensing terms.
* Docker Registry 2.5: [docker image](https://hub.docker.com/_/registry/), [license](https://github.com/docker/distribution/blob/master/LICENSE) * Docker Registry 2.5: [docker image](https://hub.docker.com/_/registry/), [license](https://github.com/docker/distribution/blob/master/LICENSE)
* MySQL 5.6: [docker image](https://hub.docker.com/_/mysql/), [license](https://github.com/docker-library/mysql/blob/master/LICENSE) * MySQL 5.6: [docker image](https://hub.docker.com/_/mysql/), [license](https://github.com/docker-library/mysql/blob/master/LICENSE)
* NGINX 1.11.5: [docker image](https://hub.docker.com/_/nginx/), [license](https://github.com/nginxinc/docker-nginx/blob/master/LICENSE) * NGINX 1.11.5: [docker image](https://hub.docker.com/_/nginx/), [license](https://github.com/nginxinc/docker-nginx/blob/master/LICENSE)
### Partners
<a href="https://www.shurenyun.com/" border="0" target="_blank"><img alt="DataMan" src="docs/img/dataman.png"></a> &nbsp; &nbsp; <a href="http://www.slamtec.com" target="_blank" border="0"><img alt="SlamTec" src="docs/img/slamteclogo.png"></a>
&nbsp; &nbsp; <a href="https://www.caicloud.io" border="0"><img alt="CaiCloud" src="docs/img/caicloudLogoWeb.png"></a>
### Users
<a href="https://www.madailicai.com/" border="0" target="_blank"><img alt="MaDaiLiCai" src="docs/img/UserMaDai.jpg"></a> <a href="https://www.dianrong.com/" border="0" target="_blank"><img alt="Dianrong" src="docs/img/dianrong.png"></a>
### Supporting Technologies
<img alt="beego" src="docs/img/beegoLogo.png"> Harbor is powered by <a href="http://beego.me/">Beego</a>.

View File

@ -0,0 +1,29 @@
# registryapi
api for docker registry by token authorization
+ a simple api class which lies in registryapi.py, which simulates the interactions
between docker registry and the vendor authorization platform like harbor.
```
usage:
from registryapi import RegistryApi
api = RegistryApi('username', 'password', 'http://www.your_registry_url.com/')
repos = api.getRepositoryList()
tags = api.getTagList('public/ubuntu')
manifest = api.getManifest('public/ubuntu', 'latest')
res = api.deleteManifest('public/ubuntu', '23424545**4343')
```
+ a simple client tool based on api class, which contains basic read and delete
operations for repo, tag, manifest
```
usage:
./cli.py --username username --password passwrod --registry_endpoint http://www.your_registry_url.com/ target action params
target can be: repo, tag, manifest
action can be: list, get, delete
params can be: --repo --ref --tag
more see: ./cli.py -h
```

135
contrib/registryapi/cli.py Executable file
View File

@ -0,0 +1,135 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# bug-report: feilengcui008@gmail.com
""" cli tool """
import argparse
import sys
import json
from registry import RegistryApi
class ApiProxy(object):
""" user RegistryApi """
def __init__(self, registry, args):
self.registry = registry
self.args = args
self.callbacks = dict()
self.register_callback("repo", "list", self.list_repo)
self.register_callback("tag", "list", self.list_tag)
self.register_callback("tag", "delete", self.delete_tag)
self.register_callback("manifest", "list", self.list_manifest)
self.register_callback("manifest", "delete", self.delete_manifest)
self.register_callback("manifest", "get", self.get_manifest)
def register_callback(self, target, action, func):
""" register real actions """
if not target in self.callbacks.keys():
self.callbacks[target] = {action: func}
return
self.callbacks[target][action] = func
def execute(self, target, action):
""" execute """
print json.dumps(self.callbacks[target][action](), indent=4, sort_keys=True)
def list_repo(self):
""" list repo """
return self.registry.getRepositoryList(self.args.num)
def list_tag(self):
""" list tag """
return self.registry.getTagList(self.args.repo)
def delete_tag(self):
""" delete tag """
(_, ref) = self.registry.existManifest(self.args.repo, self.args.tag)
if ref is not None:
return self.registry.deleteManifest(self.args.repo, ref)
return False
def list_manifest(self):
""" list manifest """
tags = self.registry.getTagList(self.args.repo)["tags"]
manifests = list()
if tags is None:
return None
for i in tags:
content = self.registry.getManifestWithConf(self.args.repo, i)
manifests.append({i: content})
return manifests
def delete_manifest(self):
""" delete manifest """
return self.registry.deleteManifest(self.args.repo, self.args.ref)
def get_manifest(self):
""" get manifest """
return self.registry.getManifestWithConf(self.args.repo, self.args.tag)
# since just a script tool, we do not construct whole target->action->args
# structure with oo abstractions which has more flexibility, just register
# parser directly
def get_parser():
""" return a parser """
parser = argparse.ArgumentParser("cli")
parser.add_argument('--username', action='store', required=True, help='username')
parser.add_argument('--password', action='store', required=True, help='password')
parser.add_argument('--registry_endpoint', action='store', required=True,
help='registry endpoint')
subparsers = parser.add_subparsers(dest='target', help='target to operate on')
# repo target
repo_target_parser = subparsers.add_parser('repo', help='target repository')
repo_target_subparsers = repo_target_parser.add_subparsers(dest='action',
help='repository subcommand')
repo_cmd_parser = repo_target_subparsers.add_parser('list', help='list repositories')
repo_cmd_parser.add_argument('--num', action='store', required=False, default=None,
help='the number of data to return')
# tag target
tag_target_parser = subparsers.add_parser('tag', help='target tag')
tag_target_subparsers = tag_target_parser.add_subparsers(dest='action',
help='tag subcommand')
tag_list_parser = tag_target_subparsers.add_parser('list', help='list tags')
tag_list_parser.add_argument('--repo', action='store', required=True, help='list tags')
tag_delete_parser = tag_target_subparsers.add_parser('delete', help='delete tag')
tag_delete_parser.add_argument('--repo', action='store', required=True, help='delete tags')
tag_delete_parser.add_argument('--tag', action='store', required=True,
help='tag reference')
# manifest target
manifest_target_parser = subparsers.add_parser('manifest', help='target manifest')
manifest_target_subparsers = manifest_target_parser.add_subparsers(dest='action',
help='manifest subcommand')
manifest_list_parser = manifest_target_subparsers.add_parser('list', help='list manifests')
manifest_list_parser.add_argument('--repo', action='store', required=True,
help='list manifests')
manifest_delete_parser = manifest_target_subparsers.add_parser('delete', help='delete manifest')
manifest_delete_parser.add_argument('--repo', action='store', required=True,
help='delete manifest')
manifest_delete_parser.add_argument('--ref', action='store', required=True,
help='manifest reference')
manifest_get_parser = manifest_target_subparsers.add_parser('get', help='get manifest content')
manifest_get_parser.add_argument('--repo', action='store', required=True, help='delete tags')
manifest_get_parser.add_argument('--tag', action='store', required=True,
help='manifest reference')
return parser
def main():
""" main entrance """
parser = get_parser()
options = parser.parse_args(sys.argv[1:])
registry = RegistryApi(options.username, options.password, options.registry_endpoint)
proxy = ApiProxy(registry, options)
proxy.execute(options.target, options.action)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,165 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# bug-report: feilengcui008@gmail.com
""" api for docker registry """
import urllib2
import urllib
import json
import base64
class RegistryException(Exception):
""" registry api related exception """
pass
class RegistryApi(object):
""" interact with docker registry and harbor """
def __init__(self, username, password, registry_endpoint):
self.username = username
self.password = password
self.basic_token = base64.encodestring("%s:%s" % (str(username), str(password)))[0:-1]
self.registry_endpoint = registry_endpoint.rstrip('/')
auth = self.pingRegistry("%s/v2/_catalog" % (self.registry_endpoint,))
if auth is None:
raise RegistryException("get token realm and service failed")
self.token_endpoint = auth[0]
self.service = auth[1]
def pingRegistry(self, registry_endpoint):
""" ping v2 registry and get realm and service """
headers = dict()
try:
res = urllib2.urlopen(registry_endpoint)
except urllib2.HTTPError as e:
headers = e.hdrs.dict
try:
(realm, service, _) = headers['www-authenticate'].split(',')
return (realm[14:-1:], service[9:-1])
except Exception as e:
return None
def getBearerTokenForScope(self, scope):
""" get bearer token from harbor """
payload = urllib.urlencode({'service': self.service, 'scope': scope})
url = "%s?%s" % (self.token_endpoint, payload)
req = urllib2.Request(url)
req.add_header('Authorization', 'Basic %s' % (self.basic_token,))
try:
response = urllib2.urlopen(req)
return json.loads(response.read())["token"]
except Exception as e:
return None
def getRepositoryList(self, n=None):
""" get repository list """
scope = "registry:catalog:*"
bear_token = self.getBearerTokenForScope(scope)
if bear_token is None:
return None
url = "%s/v2/_catalog" % (self.registry_endpoint,)
if n is not None:
url = "%s?n=%s" % (url, str(n))
req = urllib2.Request(url)
req.add_header('Authorization', r'Bearer %s' % (bear_token,))
try:
response = urllib2.urlopen(req)
return json.loads(response.read())
except Exception as e:
return None
def getTagList(self, repository):
""" get tag list for repository """
scope = "repository:%s:pull" % (repository,)
bear_token = self.getBearerTokenForScope(scope)
if bear_token is None:
return None
url = "%s/v2/%s/tags/list" % (self.registry_endpoint, repository)
req = urllib2.Request(url)
req.add_header('Authorization', r'Bearer %s' % (bear_token,))
try:
response = urllib2.urlopen(req)
return json.loads(response.read())
except Exception as e:
return None
def getManifest(self, repository, reference="latest", v1=False):
""" get manifest for tag or digest """
scope = "repository:%s:pull" % (repository,)
bear_token = self.getBearerTokenForScope(scope)
if bear_token is None:
return None
url = "%s/v2/%s/manifests/%s" % (self.registry_endpoint, repository, reference)
req = urllib2.Request(url)
req.get_method = lambda: 'GET'
req.add_header('Authorization', r'Bearer %s' % (bear_token,))
req.add_header('Accept', 'application/vnd.docker.distribution.manifest.v2+json')
if v1:
req.add_header('Accept', 'application/vnd.docker.distribution.manifest.v1+json')
try:
response = urllib2.urlopen(req)
return json.loads(response.read())
except Exception as e:
return None
def existManifest(self, repository, reference, v1=False):
""" check to see it manifest exist """
scope = "repository:%s:pull" % (repository,)
bear_token = self.getBearerTokenForScope(scope)
if bear_token is None:
raise RegistryException("manifestExist failed due to token error")
url = "%s/v2/%s/manifests/%s" % (self.registry_endpoint, repository, reference)
req = urllib2.Request(url)
req.get_method = lambda: 'HEAD'
req.add_header('Authorization', r'Bearer %s' % (bear_token,))
req.add_header('Accept', 'application/vnd.docker.distribution.manifest.v2+json')
if v1:
req.add_header('Accept', 'application/vnd.docker.distribution.manifest.v1+json')
try:
response = urllib2.urlopen(req)
return (True, response.headers.dict["docker-content-digest"])
except Exception as e:
return (False, None)
def deleteManifest(self, repository, reference):
""" delete manifest by tag """
(is_exist, digest) = self.existManifest(repository, reference)
if not is_exist:
raise RegistryException("manifest not exist")
scope = "repository:%s:pull,push" % (repository,)
bear_token = self.getBearerTokenForScope(scope)
if bear_token is None:
raise RegistryException("delete manifest failed due to token error")
url = "%s/v2/%s/manifests/%s" % (self.registry_endpoint, repository, digest)
req = urllib2.Request(url)
req.get_method = lambda: 'DELETE'
req.add_header('Authorization', r'Bearer %s' % (bear_token,))
try:
urllib2.urlopen(req)
except Exception as e:
return False
return True
def getManifestWithConf(self, repository, reference="latest"):
""" get manifest for tag or digest """
manifest = self.getManifest(repository, reference)
if manifest is None:
raise RegistryException("manifest for %s %s not exist" % (repository, reference))
config_digest = manifest["config"]["digest"]
scope = "repository:%s:pull" % (repository,)
bear_token = self.getBearerTokenForScope(scope)
if bear_token is None:
return None
url = "%s/v2/%s/blobs/%s" % (self.registry_endpoint, repository, config_digest)
req = urllib2.Request(url)
req.get_method = lambda: 'GET'
req.add_header('Authorization', r'Bearer %s' % (bear_token,))
req.add_header('Accept', 'application/vnd.docker.distribution.manifest.v2+json')
try:
response = urllib2.urlopen(req)
manifest["configContent"] = json.loads(response.read())
return manifest
except Exception as e:
return None

View File

@ -26,6 +26,9 @@ Guide to deploy Harbor on Kubenetes. (maintained by community)
[Architecture Overview of Harbor](https://github.com/vmware/harbor/wiki/Architecture-Overview-of-Harbor) [Architecture Overview of Harbor](https://github.com/vmware/harbor/wiki/Architecture-Overview-of-Harbor)
Developers read this first. Developers read this first.
[Build Harbor from Source](compile_guide.md)
How to build Harbor from source code.
[Harbor API Specs by Swagger](configure_swagger.md) [Harbor API Specs by Swagger](configure_swagger.md)
Use Swagger to find out the specs of Harbor API. Use Swagger to find out the specs of Harbor API.

View File

@ -1,65 +1,142 @@
## makeing Harbor on Kubernetes
To deploy Harbor on Kubernetes, it requires some additional steps because
1. When Harbor registry uses https, so we need cert or workaround to avoid errors like this:
```
Error response from daemon: invalid registry endpoint https://{HOST}/v0/: unable to ping registry endpoint https://{HOST}/v0/
v2 ping attempt failed with error: Get https://{HOST}/v2/: EOF
v1 ping attempt failed with error: Get https://{HOST}/v1/_ping: EOF. If this private registry supports only HTTP or HTTPS with an unknown CA certificate, please add `--insecure-registry {HOST}` to the daemon's arguments. In the case of HTTPS, if you have access to the registry's CA certificate, no need for the flag; simply place the CA certificate at /etc/docker/certs.d/{HOST}/ca.crt
```
There is a workaround if you don't have a cert. The workaround is to add the host into the list of insecure registry by editting the ```/etc/default/docker``` file:
```
sudo vi /etc/default/docker
```
add the line at the end of file:
```
DOCKER_OPTS="$DOCKER_OPTS --insecure-registry={HOST}"
```
restart docker service
```
sudo service docker restart
```
2. The registry config file needs to have the IP (or DNS name) of the registry, but on Kubernetes, you don't know the IP before the service is created. There are several workarounds to solve this problem for now: ## Integration with Kubernetes
- Use DNS name and link the DNS name with the IP after the service is created. This Document decribes how to deploy Harbor on Kubernetes.
- Rebuild the registry image with the service IP after the service is created and use ```kubectl rolling-update``` to update to the new image.
### Prerequisite
* You need to download docker images of Harbor.
* Download the offline installer of Harbor from the [release](https://github.com/vmware/harbor/releases) page.
* Uncompress the offline installer and get the images tgz file harbor.*.tgz.
* Load the images into docker:
```
docker load -i harbor.*.tgz
```
* You should have domain knowledge about Kubernetes (Replication Controller, Service, Persistent Volume, Persistent Volume Claim, Config Map).
To start Harbor on Kubernetes, you first need to build the docker images. The docker images for deploying Harbor on Kubernetes depends on the docker images to deploy Harbor with docker-compose. So the first step is to build docker images with docker-compose. Before actually building the images, you need to first adjust the [configuration](https://github.com/vmware/harbor/blob/master/make/harbor.cfg): ### Configuration
- Change the [hostname](https://github.com/vmware/harbor/blob/master/make/harbor.cfg#L5) to ```localhost``` We provide a python script `make/kubernetes/prepare` to generate Kubernetes ConfigMap files.
- Adjust the [email settings](https://github.com/vmware/harbor/blob/master/make/harbor.cfg#L11) according to your needs. The script is written in python, so you need a version of python in your deployment environment.
Also the script need `openssl` to generate private key and certification, make sure you have a workable `openssl`.
There are some args of the python script:
- -f: Default Value is `../harbor.cfg`. You can specify other config file of Harbor.
- -k: Path to https private key. This arg can overwrite the value of `ssl_cert_key` in `harbor.cfg`.
- -c: Path to https certification. This arg can overwrite the value of `ssl_cert` in `harbor.cfg`.
- -s: Path to secret key. Must be 16 characters. If you don't set it, the script will generate it automatically.
#### Basic Configuration
These Basic Configuration must be set. Otherwise you can't deploy Harbor on Kubernetes.
- `make/harbor.cfg`: Basic config of Harbor. Please refer to `harbor.cfg`.
- `make/kubernetes/**/*.rc.yaml`: Specify configs of containers.
You need to specify the path to your images in all `*.rc.yaml`. example:
```
containers:
- name: nginx-app
# it's very importent that you need modify the path of image.
image: harbor/nginx
```
- `make/kubernetes/pv/*.pvc.yaml`: Persistent Volume Claim.
You can set capacity of storage in these files. example:
```
resources:
requests:
# you can set another value to adapt to your needs
storage: 100Gi
```
- `make/kubernetes/pv/*.pv.yaml`: Persistent Volume. Be bound with `*.pvc.yaml`.
PVs and PVCs are one to one correspondence. If you changed capacity of PVC, you need to set capacity of PV together.
example:
```
capacity:
# same value with PVC
storage: 100Gi
```
In PV, you should set another way to store data rather than `hostPath`:
```
# it's default value, you should use others like nfs.
hostPath:
path: /data/registry
```
For more infomation about store ways, Please check [Kubernetes Document](http://kubernetes.io/docs/user-guide/persistent-volumes/)
Then you can generate ConfigMap files by :
Then you can run the following commends to build docker images:
``` ```
cd make python make/kubernetes/prepare
./prepare
docker-compose build
docker build -f kubernetes/dockerfiles/proxy-dockerfile -t {your_account}/proxy .
docker build -f kubernetes/dockerfiles/registry-dockerfile -t {your_account}/registry .
docker build -f kubernetes/dockerfiles/ui-dockerfile -t {your_account}/deploy_ui .
docker tag deploy_mysql {your_account}/deploy_mysql
docker push {your_account}/proxy
docker push {your_account}/registry
docker push {your_account}/deploy_ui
docker push {your_account}/deploy_mysql
``` ```
where "your_account" is your own registry. Then you need to update the "image" field in the ```*-rc.yaml``` files at: These files will be generated:
``` - make/kubernetes/jobservice/jobservice.cm.yaml
make/kubernetes/mysql-rc.yaml - make/kubernetes/mysql/mysql.cm.yaml
make/kubernetes/proxy-rc.yaml - make/kubernetes/nginx/nginx.cm.yaml
make/kubernetes/registry-rc.yaml - make/kubernetes/registry/registry.cm.yaml
make/kubernetes/ui-rc.yaml - make/kubernetes/ui/ui.cm.yaml
```
Further more, the following configuration could be changed according to your need: #### Advanced Configuration
- **harbor_admin_password**: The password for the administrator of Harbor, by default the password is Harbor12345. You can changed it [here](https://github.com/vmware/harbor/blob/master/make/kubernetes/ui-rc.yaml#L36). If Basic Configuration was not covering your requirements, you can read this section for more details.
- **auth_mode**: The authentication mode of Harbor. By default it is *db_auth*, i.e. the credentials are stored in a database. Please set it to *ldap_auth* if you want to verify user's credentials against an LDAP server. You can change the configuration [here](https://github.com/vmware/harbor/blob/master/make/kubernetes/ui-rc.yaml#L40).
- **ldap_url**: The URL for LDAP endpoint, for example ldaps://ldap.mydomain.com. It is only used when **auth_mode** is set to *ldap_auth*. It could be changed [here](https://github.com/vmware/harbor/blob/master/make/kubernetes/ui-rc.yaml#L42).
- **ldap_basedn**: The basedn template for verifying the user's credentials against LDAP, for example uid=%s,ou=people,dc=mydomain,dc=com. It is only used when **auth_mode** is set to *ldap_auth*. It could be changed [here](https://github.com/vmware/harbor/blob/master/make/kubernetes/ui-rc.yaml#L44).
- **db_password**: The password of root user of mySQL database. Change this password for any production use. You need to change both [here](https://github.com/vmware/harbor/blob/master/make/kubernetes/ui-rc.yaml#L28) and [here](https://github.com/vmware/harbor/blob/master/make/harbor.cfg#L32) to make the change. Please note, you need to change the ```harbor.cfg``` before building the docker images.
Finally you can start the jobs by running: `./prepare` has a specify format of placeholder:
``` - `{{key}}`: It means we should replace the placeholder with the value in `config.cfg` which name is `key`.
kubectl create -f make/kubernetes - `{{num key}}`: It's used for multiple lines text. It will add `num` spaces to the leading of every line in text.
```
You can find all configs of Harbor in `make/kubernetes/templates/`. There are specifications of these files:
- `jobservice.cm.yaml`: ENV and web config of jobservice
- `mysql.cm.yaml`: Root passowrd of MySQL
- `nginx.cm.yaml`: Https certification and nginx config. If you are fimiliar with nginx, you can modify it.
- `registry.cm.yaml`: Token service certification and registry config
Registry use filesystem to store data of images. You can find it like:
```
storage:
filesystem:
rootdirectory: /storage
```
If you want use another storage backend, please see [Docker Doc](https://docs.docker.com/datacenter/dtr/2.1/guides/configure/configure-storage/)
- `ui.cm.yaml`: Token service private key, ENV and web config of ui
`ui` and `jobservice` are powered by beego. If you are fimiliar with beego, you can modify configs in `jobservice.cm.yaml` and `ui.cm.yaml`.
### Running
When you finished your configuring and generated ConfigMap files, you can run Harbor on kubernetes with these commands:
```
# create pv & pvc
kubectl apply -f make/kubernetes/pv/log.pv.yaml
kubectl apply -f make/kubernetes/pv/registry.pv.yaml
kubectl apply -f make/kubernetes/pv/storage.pv.yaml
kubectl apply -f make/kubernetes/pv/log.pvc.yaml
kubectl apply -f make/kubernetes/pv/registry.pvc.yaml
kubectl apply -f make/kubernetes/pv/storage.pvc.yaml
# create config map
kubectl apply -f make/kubernetes/jobservice/jobservice.cm.yaml
kubectl apply -f make/kubernetes/mysql/mysql.cm.yaml
kubectl apply -f make/kubernetes/nginx/nginx.cm.yaml
kubectl apply -f make/kubernetes/registry/registry.cm.yaml
kubectl apply -f make/kubernetes/ui/ui.cm.yaml
# create service
kubectl apply -f make/kubernetes/jobservice/jobservice.svc.yaml
kubectl apply -f make/kubernetes/mysql/mysql.svc.yaml
kubectl apply -f make/kubernetes/nginx/nginx.svc.yaml
kubectl apply -f make/kubernetes/registry/registry.svc.yaml
kubectl apply -f make/kubernetes/ui/ui.svc.yaml
# create k8s rc
kubectl apply -f make/kubernetes/registry/registry.rc.yaml
kubectl apply -f make/kubernetes/mysql/mysql.rc.yaml
kubectl apply -f make/kubernetes/jobservice/jobservice.rc.yaml
kubectl apply -f make/kubernetes/ui/ui.rc.yaml
kubectl apply -f make/kubernetes/nginx/nginx.rc.yaml
```

View File

@ -9,23 +9,21 @@ When upgrading your existing Habor instance to a newer version, you may need to
### Upgrading Harbor and migrating data ### Upgrading Harbor and migrating data
1. Log in to the machine that Harbor runs on, stop and remove existing Harbor service if it is still running: 1. Log in to the host that Harbor runs on, stop and remove existing Harbor instance if it is still running:
``` ```
cd make/ cd harbor
docker-compose down docker-compose down
``` ```
2. Back up Harbor's current source code so that you can roll back to the current version when it is necessary. 2. Back up Harbor's current files so that you can roll back to the current version when it is necessary.
```sh ```sh
cd ../.. cd ..
mv harbor /tmp/harbor mv harbor /tmp/harbor
``` ```
3. Get the lastest source code from Github: 3. Get the lastest Harbor release package from Github:
```sh https://github.com/vmware/harbor/releases
git clone https://github.com/vmware/harbor
```
4. Before upgrading Harbor, perform database migration first. The migration tool is delivered as a docker image, so you should pull the image from docker hub: 4. Before upgrading Harbor, perform database migration first. The migration tool is delivered as a docker image, so you should pull the image from docker hub:
@ -45,16 +43,13 @@ When upgrading your existing Habor instance to a newer version, you may need to
docker run -ti --rm -e DB_USR=root -e DB_PWD=xxxx -v /data/database:/var/lib/mysql vmware/harbor-db-migrator up head docker run -ti --rm -e DB_USR=root -e DB_PWD=xxxx -v /data/database:/var/lib/mysql vmware/harbor-db-migrator up head
``` ```
7. Change to `make/` directory, configure Harbor by modifying the file `harbor.cfg`, you may need to refer to the configuration files you've backed up during step 2. Refer to [Installation & Configuration Guide ](../docs/installation_guide.md) for more info. 7. Unzip the new Harbor package and change to `./harbor` as the working directory. Configure Harbor by modifying the file `harbor.cfg`,
you may need to refer to the configuration files you've backed up during step 2.
Refer to [Installation & Configuration Guide ](../docs/installation_guide.md) for more information.
Since the content and format of `harbor.cfg` may have been changed in the new release, **DO NOT directly copy `harbor.cfg` from previous version of Harbor.**
8. Under the directory `make/`, run the `./prepare` script to generate necessary config files. 8. Under the directory `./harbor`, run the `./install.sh` script to install the new Harbor instance.
9. Rebuild Harbor and restart the registry service
```
docker-compose up --build -d
```
### Roll back from an upgrade ### Roll back from an upgrade
For any reason, if you want to roll back to the previous version of Harbor, follow the below steps: For any reason, if you want to roll back to the previous version of Harbor, follow the below steps:
@ -62,7 +57,7 @@ For any reason, if you want to roll back to the previous version of Harbor, foll
1. Stop and remove the current Harbor service if it is still running. 1. Stop and remove the current Harbor service if it is still running.
``` ```
cd make/ cd harbor
docker-compose down docker-compose down
``` ```
2. Restore database from backup file in `/path/to/backup` . 2. Restore database from backup file in `/path/to/backup` .
@ -71,19 +66,26 @@ For any reason, if you want to roll back to the previous version of Harbor, foll
docker run -ti --rm -e DB_USR=root -e DB_PWD=xxxx -v /data/database:/var/lib/mysql -v /path/to/backup:/harbor-migration/backup vmware/harbor-db-migrator restore docker run -ti --rm -e DB_USR=root -e DB_PWD=xxxx -v /data/database:/var/lib/mysql -v /path/to/backup:/harbor-migration/backup vmware/harbor-db-migrator restore
``` ```
3. Remove current source code of Harbor. 3. Remove current Harbor instance.
``` ```
rm -rf harbor rm -rf harbor
``` ```
4. Restore the source code of an older version of Harbor. 4. Restore the older version package of Harbor.
```sh ```sh
mv /tmp/harbor harbor mv /tmp/harbor harbor
``` ```
5. Restart Harbor service using the previous configuration. 5. Restart Harbor service using the previous configuration.
If previous version of Harbor was installed by a release build:
```sh ```sh
cd make/ cd harbor
./install.sh
```
If your previous version of Harbor was installed from source code:
```sh
cd harbor
docker-compose up --build -d docker-compose up --build -d
``` ```

View File

@ -1,3 +0,0 @@
FROM library/nginx:1.11.5
ADD ./config/nginx /etc/nginx

View File

@ -1,33 +0,0 @@
version: 0.1
log:
level: debug
fields:
service: registry
storage:
cache:
layerinfo: inmemory
filesystem:
rootdirectory: /storage
maintenance:
uploadpurging:
enabled: false
http:
addr: :5000
secret: placeholder
debug:
addr: localhost:5001
auth:
token:
issuer: registry-token-issuer
realm: http://harbor.caicloud.io/service/token
rootcertbundle: /etc/registry/root.crt
service: token-service
notifications:
endpoints:
- name: harbor
disabled: false
url: http://harbor.caicloud.io/service/notifications
timeout: 500
threshold: 5
backoff: 1000

View File

@ -1,6 +0,0 @@
FROM library/registry:2.3.0
ADD ./config/registry/ /etc/registry/
ADD ./kubernetes/dockerfiles/registry-config.yml /etc/registry/config.yml
CMD ["/etc/registry/config.yml"]

View File

@ -1,4 +0,0 @@
FROM deploy_ui
ADD ./config/ui/app.conf /etc/ui/app.conf
ADD ./config/ui/private_key.pem /etc/ui/private_key.pem

View File

@ -0,0 +1,112 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: jobservice-rc
labels:
name: jobservice-rc
spec:
replicas: 1
selector:
name: jobservice-apps
template:
metadata:
labels:
name: jobservice-apps
spec:
containers:
- name: jobservice-app
image: harbor/jobservice
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_HOST
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: MYSQL_HOST
- name: MYSQL_PORT
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: MYSQL_PORT
- name: MYSQL_USR
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: MYSQL_USR
- name: MYSQL_PWD
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: MYSQL_PWD
- name: UI_SECRET
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: UI_SECRET
- name: SECRET_KEY
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: SECRET_KEY
- name: CONFIG_PATH
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: CONFIG_PATH
- name: REGISTRY_URL
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: REGISTRY_URL
- name: VERIFY_REMOTE_CERT
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: VERIFY_REMOTE_CERT
- name: MAX_JOB_WORKERS
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: MAX_JOB_WORKERS
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: LOG_LEVEL
- name: LOG_DIR
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: LOG_DIR
- name: GODEBUG
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: GODEBUG
- name: EXT_ENDPOINT
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: EXT_ENDPOINT
- name: TOKEN_URL
valueFrom:
configMapKeyRef:
name: harbor-jobservice-config
key: TOKEN_URL
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /etc/jobservice
- name: logs
mountPath: /var/log/jobs
volumes:
- name: config
configMap:
name: harbor-jobservice-config
items:
- key: config
path: app.conf
- name: logs
persistentVolumeClaim:
claimName: log-pvc

View File

@ -0,0 +1,9 @@
apiVersion: v1
kind: Service
metadata:
name: jobservice
spec:
ports:
- port: 80
selector:
name: jobservice-apps

View File

@ -1,30 +1,34 @@
apiVersion: v1 apiVersion: v1
kind: ReplicationController kind: ReplicationController
metadata: metadata:
name: mysql name: mysql-rc
labels: labels:
name: mysql name: mysql-rc
spec: spec:
replicas: 1 replicas: 1
selector: selector:
name: mysql name: mysql-apps
template: template:
metadata: metadata:
labels: labels:
name: mysql name: mysql-apps
spec: spec:
containers: containers:
- name: mysql - name: mysql-app
image: caicloud/harbor_deploy_mysql:latest image: harbor/mysql
imagePullPolicy: Always imagePullPolicy: IfNotPresent
ports: ports:
- containerPort: 3306 - containerPort: 3306
env: env:
- name: MYSQL_ROOT_PASSWORD - name: MYSQL_ROOT_PASSWORD
value: root123 valueFrom:
configMapKeyRef:
name: harbor-mysql-config
key: MYSQL_ROOT_PASSWORD
volumeMounts: volumeMounts:
- name: mysql-storage - name: mysql-storage
mountPath: /var/lib/mysql mountPath: /var/lib/mysql
volumes: volumes:
- name: mysql-storage - name: mysql-storage
emptyDir: {} persistentVolumeClaim:
claimName: storage-pvc

View File

@ -2,10 +2,8 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: mysql name: mysql
labels:
name: mysql
spec: spec:
ports: ports:
- port: 3306 - port: 3306
selector: selector:
name: mysql name: mysql-apps

View File

@ -0,0 +1,36 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx-rc
labels:
name: nginx-rc
spec:
replicas: 1
selector:
name: nginx-apps
template:
metadata:
labels:
name: nginx-apps
spec:
containers:
- name: nginx-app
image: harbor/nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
- containerPort: 443
volumeMounts:
- name: config
mountPath: /etc/nginx
volumes:
- name: config
configMap:
name: harbor-nginx-config
items:
- key: config
path: nginx.conf
- key: pkey
path: https.key
- key: cert
path: https.crt

View File

@ -1,15 +1,12 @@
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: proxy name: nginx
labels:
name: proxy
spec: spec:
type: LoadBalancer
ports: ports:
- name: http - name: http
port: 80 port: 80
- name: https - name: https
port: 443 port: 443
selector: selector:
name: proxy name: nginx-apps

201
make/kubernetes/prepare Normal file
View File

@ -0,0 +1,201 @@
#!/usr/bin/env python
from __future__ import print_function, unicode_literals # We require Python 2.6 or later
import sys
import argparse
import io
import os
import random
import re
import string
import subprocess
if sys.version_info[:3][0] == 2:
import ConfigParser as configparser
import StringIO as io
if sys.version_info[:3][0] == 3:
import configparser as configparser
import io as io
# prepare base dir
base_dir = os.path.dirname(os.path.abspath(__file__))
parser = argparse.ArgumentParser(description='Generate *.cm.yaml')
parser.add_argument('-f', default=os.path.join(base_dir, '../harbor.cfg'),
dest='config_file', help='[Optional] path of harbor config file')
parser.add_argument('-k', default='',
dest='private_key', help='[Optional] path of harbor https private key(pem)')
parser.add_argument('-c', default='',
dest='cert', help='[Optional] harbor path of https cert(pem)')
parser.add_argument('-s', default='',
dest='secret_key', help="[Optional] path of harbor secret key(16 characters)")
args = parser.parse_args()
# read config file
config_str = ''
if os.path.isfile(args.config_file):
with open(args.config_file) as conf:
config_str = conf.read()
else:
raise Exception('Error: No such file(' + args.config_file + ')')
config_str = '[harbor]\n' + config_str
fp = io.StringIO()
fp.write(config_str)
fp.seek(0, os.SEEK_SET)
config = configparser.RawConfigParser()
config.readfp(fp)
def get_config(key):
"""get value by key
"""
if config.has_option('harbor', key):
return config.get('harbor', key)
print('Warning: Key(' + key + ') is not existing. Use empty string as default')
return ''
def set_config(key, value):
"""set key & value
"""
config.set('harbor', key, value)
# relative path with config file
def rel_path(p):
if p[0] == '/':
return p
config_path = args.config_file
if config_path[0] != '/':
config_path = os.path.join(os.getcwd(), config_path)
return os.path.join(os.path.dirname(config_path), p)
# path of private key
pk_path = args.private_key
if pk_path == '':
pk_path = get_config('ssl_cert_key')
if pk_path != '':
pk_path = rel_path(pk_path)
# path of cert
cert_path = args.cert
if cert_path == '':
cert_path = get_config('ssl_cert')
if cert_path != '':
cert_path = rel_path(cert_path)
# validate
if get_config('ui_url_protocol') == 'https':
if pk_path == '':
raise Exception("Error: The protocol is https but attribute ssl_cert_key is not set")
if cert_path == '':
raise Exception("Error: The protocol is https but attribute ssl_cert is not set")
else:
pk_path = ''
cert_path = ''
# read secret key
if args.secret_key != '':
if os.path.isfile(args.secret_key):
key = ''
with open(args.secret_key, 'r') as skey:
key = skey.read()
if len(key) != 16:
raise Exception('Error: The length of secret key has to be 16 characters!')
set_config('secret_key', key)
else:
set_config('secret_key', ''.join(random.choice(
string.ascii_letters + string.digits) for i in range(16)))
# read https pkey & cert
if pk_path != '':
if os.path.isfile(pk_path):
with open(pk_path, 'r') as pkey:
set_config('https_pkey', pkey.read())
else:
raise Exception('Error: https private key is not existing')
else:
set_config('https_pkey', 'USE_HTTP')
if cert_path != '':
if os.path.isfile(cert_path):
with open(cert_path, 'r') as cert:
set_config('https_cert', cert.read())
else:
raise Exception('Error: https cert is not existing')
else:
set_config('https_cert', 'USE_HTTP')
# add configs
set_config('ui_url', get_config('ui_url_protocol') +
'://' + get_config('hostname'))
set_config('ui_secret', ''.join(random.choice(
string.ascii_letters + string.digits) for i in range(16)))
# generate auth pkey & cert
with open(os.devnull, 'w') as devnull:
openssl = subprocess.call(['which','openssl'], stdout=devnull, stderr=devnull)
if openssl == 0:
pkey = subprocess.check_output(['openssl','genrsa','4096'], stderr=devnull)
subj = '/C={0}/ST={1}/L={2}/O={3}/OU={4}/CN={5}/emailAddress={6}'.format(get_config('crt_country'),
get_config('crt_state'), get_config('crt_location'), get_config('crt_organization'),
get_config('crt_organizationalunit'), get_config('crt_commonname'), get_config('crt_email'))
openssl = subprocess.Popen(['openssl', 'req', '-new', '-x509', '-key', '/dev/stdin', '-days', '3650', '-subj', subj],
stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=devnull)
cert = openssl.communicate(input=pkey)[0]
set_config('auth_pkey', pkey.decode())
set_config('auth_cert', cert.decode())
else:
set_config('auth_pkey', 'NEED_SET')
set_config('auth_cert', 'NEED_SET')
print('Warning: auth_pkey and auth_cert cannot be generated automatically without openssl. Please set it manually')
variable = re.compile(r'{{.+?}}')
detail = re.compile(r'((\d+) )?([a-zA-Z_0-9-]+)')
def render_template(tmpl):
"""render template
replace {{(number of leading spaces)name}} with config
examples:
config:
hostname='test\ntest'
{{hostname}} -> 'test\ntest'
{{4 hostname}} -> 'test\n test'
"""
matches = variable.findall(tmpl)
for match in matches:
segs = detail.search(match)
if segs.group() == '':
raise Exception('Error: Invalid template item(' + match + ')')
value = get_config(segs.group(3))
spaces = segs.group(2)
if spaces != '' and spaces != None:
leading = ''.join(' ' for i in range(int(spaces)))
value = str(value).replace('\n', '\n' + leading)
tmpl = tmpl.replace(match, value)
return tmpl
def generate_template(tmpl, dest):
"""generate file
"""
with open(tmpl) as tmpl:
with open(dest, 'w') as dest:
dest.write(render_template(tmpl.read()))
template_dir = os.path.join(base_dir, 'templates')
output_dir = base_dir
generate_template(os.path.join(template_dir, 'ui.cm.yaml'), os.path.join(output_dir, 'ui/ui.cm.yaml'))
generate_template(os.path.join(template_dir, 'jobservice.cm.yaml'), os.path.join(output_dir, 'jobservice/jobservice.cm.yaml'))
generate_template(os.path.join(template_dir, 'mysql.cm.yaml'), os.path.join(output_dir, 'mysql/mysql.cm.yaml'))
generate_template(os.path.join(template_dir, 'nginx.cm.yaml'), os.path.join(output_dir, 'nginx/nginx.cm.yaml'))
generate_template(os.path.join(template_dir, 'registry.cm.yaml'), os.path.join(output_dir, 'registry/registry.cm.yaml'))

View File

@ -1,22 +0,0 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: proxy
labels:
name: proxy
spec:
replicas: 1
selector:
name: proxy
template:
metadata:
labels:
name: proxy
spec:
containers:
- name: proxy
image: caicloud/harbor_proxy:latest
imagePullPolicy: Always
ports:
- containerPort: 80
- containerPort: 443

View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: log-pv
labels:
type: log
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /data/logs

View File

@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: log-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
selector:
matchLabels:
type: log

View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: registry-pv
labels:
type: registry
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /data/registry

View File

@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: registry-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
selector:
matchLabels:
type: registry

View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: storage-pv
labels:
type: storage
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /data/storage

View File

@ -0,0 +1,13 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: storage-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
selector:
matchLabels:
type: storage

View File

@ -1,28 +0,0 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: registry
labels:
name: registry
spec:
replicas: 1
selector:
name: registry
template:
metadata:
labels:
name: registry
spec:
containers:
- name: registry
image: caicloud/harbor_registry:2.3.0
imagePullPolicy: Always
ports:
- containerPort: 5000
- containerPort: 5001
volumeMounts:
- name: storage
mountPath: /storage
volumes:
- name: storage
emptyDir: {}

View File

@ -0,0 +1,39 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: registry-rc
labels:
name: registry-rc
spec:
replicas: 1
selector:
name: registry-apps
template:
metadata:
labels:
name: registry-apps
spec:
containers:
- name: registry-app
image: harbor/registry
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
- containerPort: 5001
volumeMounts:
- name: config
mountPath: /etc/docker/registry
- name: storage
mountPath: /storage
volumes:
- name: config
configMap:
name: harbor-registry-config
items:
- key: config
path: config.yml
- key: cert
path: root.crt
- name: storage
persistentVolumeClaim:
claimName: registry-pvc

View File

@ -2,13 +2,11 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: registry name: registry
labels:
name: registry
spec: spec:
ports: ports:
- name: internal - name: repo
port: 5000 port: 5000
- name: external - name: debug
port: 5001 port: 5001
selector: selector:
name: registry name: registry-apps

View File

@ -0,0 +1,25 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: harbor-jobservice-config
data:
MYSQL_HOST: mysql
MYSQL_PORT: "3306"
MYSQL_USR: root
MYSQL_PWD: "{{db_password}}"
UI_SECRET: "{{ui_secret}}"
SECRET_KEY: "{{secret_key}}"
CONFIG_PATH: /etc/jobservice/app.conf
REGISTRY_URL: http://registry:5000
VERIFY_REMOTE_CERT: "{{verify_remote_cert}}"
MAX_JOB_WORKERS: "{{max_job_workers}}"
LOG_LEVEL: debug
LOG_DIR: /var/log/jobs
GODEBUG: netdns=cgo
EXT_ENDPOINT: "{{ui_url}}"
TOKEN_URL: http://ui
config: |
appname = jobservice
runmode = dev
[dev]
httpport = 80

View File

@ -0,0 +1,6 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: harbor-mysql-config
data:
MYSQL_ROOT_PASSWORD: "{{db_password}}"

View File

@ -0,0 +1,155 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: harbor-nginx-config
data:
config: |
worker_processes auto;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
tcp_nodelay on;
# this is necessary for us to be able to disable request buffering in all cases
proxy_http_version 1.1;
upstream registry {
server registry:5000;
}
upstream ui {
server ui:80;
}
server {
listen 443 ssl;
server_name {{hostname}};
# SSL
ssl_certificate /etc/nginx/https.crt;
ssl_certificate_key /etc/nginx/https.key;
# Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
chunked_transfer_encoding on;
location / {
proxy_pass http://ui/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
}
location /v1/ {
return 404;
}
location /v2/ {
proxy_pass http://registry/v2/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
}
location /service/ {
proxy_pass http://ui/service/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
}
}
server {
listen 80;
server_name {{hostname}};
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
chunked_transfer_encoding on;
# rewrite ^/(.*) https://$server_name:443/$1 permanent;
location / {
proxy_pass http://ui/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
}
location /v1/ {
return 404;
}
location /v2/ {
proxy_pass http://registry/v2/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
}
location /service/ {
proxy_pass http://ui/service/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
}
}
}
pkey: |
{{4 https_pkey}}
cert: |
{{4 https_cert}}

View File

@ -0,0 +1,44 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: harbor-registry-config
data:
config: |
version: 0.1
log:
level: debug
fields:
service: registry
storage:
filesystem:
rootdirectory: /storage
cache:
layerinfo: inmemory
maintenance:
uploadpurging:
enabled: false
delete:
enabled: true
http:
addr: :5000
secret: placeholder
debug:
addr: localhost:5001
auth:
token:
issuer: registry-token-issuer
realm: {{ui_url}}/service/token
rootcertbundle: /etc/docker/registry/root.crt
service: token-service
notifications:
endpoints:
- name: harbor
disabled: false
url: http://ui/service/notifications
timeout: 3000ms
threshold: 5
backoff: 1s
cert: |
{{4 auth_cert}}

View File

@ -0,0 +1,52 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: harbor-ui-config
data:
MYSQL_HOST: mysql
MYSQL_PORT: "3306"
MYSQL_USR: root
MYSQL_PWD: "{{db_password}}"
REGISTRY_URL: http://registry:5000
CONFIG_PATH: /etc/ui/app.conf
HARBOR_REG_URL: "{{hostname}}"
HARBOR_ADMIN_PASSWORD: "{{harbor_admin_password}}"
HARBOR_URL: http://ui
AUTH_MODE: "{{auth_mode}}"
LDAP_URL: "{{ldap_url}}"
LDAP_SEARCH_DN: "{{ldap_searchdn}}"
LDAP_SEARCH_PWD: "{{ldap_search_pwd}}"
LDAP_BASE_DN: "{{ldap_basedn}}"
LDAP_FILTER: "{{ldap_filter}}"
LDAP_UID: "{{ldap_uid}}"
LDAP_SCOPE: "{{ldap_scope}}"
LOG_LEVEL: debug
UI_SECRET: "{{ui_secret}}"
SECRET_KEY: "{{secret_key}}"
GODEBUG: netdns=cgo
EXT_ENDPOINT: "{{ui_url}}"
TOKEN_URL: http://ui
SELF_REGISTRATION: "{{self_registration}}"
USE_COMPRESSED_JS: "{{use_compressed_js}}"
VERIFY_REMOTE_CERT: "{{verify_remote_cert}}"
TOKEN_EXPIRATION: "{{token_expiration}}"
EXT_REG_URL: "{{hostname}}"
config: |
appname = registry
runmode = dev
[lang]
types = en-US|zh-CN
names = en-US|zh-CN
[dev]
httpport = 80
[mail]
host = {{email_server}}
port = {{email_server_port}}
username = {{email_username}}
password = {{email_password}}
from = {{email_from}}
ssl = {{email_ssl}}
pkey: |
{{4 auth_pkey}}

View File

@ -1,49 +0,0 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: ui
labels:
name: ui
spec:
replicas: 1
selector:
name: ui
template:
metadata:
labels:
name: ui
spec:
containers:
- name: ui
image: caicloud/harbor_deploy_ui:latest
imagePullPolicy: Always
env:
- name: MYSQL_HOST
value: mysql
- name: MYSQL_PORT
value: "3306"
- name: MYSQL_USR
value: root
- name: MYSQL_PWD
value: root123
- name: REGISTRY_URL
value: http://registry:5000
- name: CONFIG_PATH
value: /etc/ui/app.conf
- name: HARBOR_REG_URL
value: localhost
- name: HARBOR_ADMIN_PASSWORD
value: Harbor12345
- name: HARBOR_URL
value: http://localhost
- name: AUTH_MODE
value: db_auth
- name: LDAP_URL
value: ldaps://ldap.mydomain.com
- name: LDAP_BASE_DN
value: uid=%s,ou=people,dc=mydomain,dc=com
- name: LOG_LEVEL
value: debug
ports:
- containerPort: 80

View File

@ -0,0 +1,174 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: ui-rc
labels:
name: ui-rc
spec:
replicas: 1
selector:
name: ui-apps
template:
metadata:
labels:
name: ui-apps
spec:
containers:
- name: ui-app
image: harbor/ui
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_HOST
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: MYSQL_HOST
- name: MYSQL_PORT
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: MYSQL_PORT
- name: MYSQL_USR
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: MYSQL_USR
- name: MYSQL_PWD
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: MYSQL_PWD
- name: REGISTRY_URL
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: REGISTRY_URL
- name: CONFIG_PATH
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: CONFIG_PATH
- name: HARBOR_REG_URL
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: HARBOR_REG_URL
- name: HARBOR_ADMIN_PASSWORD
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: HARBOR_ADMIN_PASSWORD
- name: HARBOR_URL
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: HARBOR_URL
- name: AUTH_MODE
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: AUTH_MODE
- name: LDAP_URL
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: LDAP_URL
- name: LDAP_SEARCH_DN
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: LDAP_SEARCH_DN
- name: LDAP_SEARCH_PWD
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: LDAP_SEARCH_PWD
- name: LDAP_BASE_DN
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: LDAP_BASE_DN
- name: LDAP_FILTER
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: LDAP_FILTER
- name: LDAP_UID
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: LDAP_UID
- name: LDAP_SCOPE
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: LDAP_SCOPE
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: LOG_LEVEL
- name: UI_SECRET
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: UI_SECRET
- name: SECRET_KEY
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: SECRET_KEY
- name: GODEBUG
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: GODEBUG
- name: EXT_ENDPOINT
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: EXT_ENDPOINT
- name: TOKEN_URL
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: TOKEN_URL
- name: SELF_REGISTRATION
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: SELF_REGISTRATION
- name: USE_COMPRESSED_JS
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: USE_COMPRESSED_JS
- name: VERIFY_REMOTE_CERT
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: VERIFY_REMOTE_CERT
- name: TOKEN_EXPIRATION
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: TOKEN_EXPIRATION
- name: EXT_REG_URL
valueFrom:
configMapKeyRef:
name: harbor-ui-config
key: EXT_REG_URL
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /etc/ui
volumes:
- name: config
configMap:
name: harbor-ui-config
items:
- key: config
path: app.conf
- key: pkey
path: private_key.pem

View File

@ -2,10 +2,8 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: ui name: ui
labels:
name: ui
spec: spec:
ports: ports:
- port: 80 - port: 80
selector: selector:
name: ui name: ui-apps

13
partners.md Normal file
View File

@ -0,0 +1,13 @@
# Community of Harbor
Below are some of the partners and users of Harbor projects ( update constantly ). If you wish to be listed on this page as reference partners or users, please contact us at harbor@ vmware.com .
## Partners
<a href="https://www.shurenyun.com/" border="0" target="_blank"><img alt="DataMan" src="docs/img/dataman.png"></a> &nbsp; &nbsp; <a href="http://www.slamtec.com" target="_blank" border="0"><img alt="SlamTec" src="docs/img/slamteclogo.png"></a>
&nbsp; &nbsp; <a href="https://www.caicloud.io" border="0"><img alt="CaiCloud" src="docs/img/caicloudLogoWeb.png"></a>
## Users
<a href="https://www.madailicai.com/" border="0" target="_blank"><img alt="MaDaiLiCai" src="docs/img/UserMaDai.jpg"></a> <a href="https://www.dianrong.com/" border="0" target="_blank"><img alt="Dianrong" src="docs/img/dianrong.png"></a>
## Supporting Technologies
<img alt="beego" src="docs/img/beegoLogo.png"> Harbor is powered by <a href="http://beego.me/">Beego</a>.