diff --git a/lib/manager/azure-pipelines/__fixtures__/azure-pipelines-invalid.yaml b/lib/manager/azure-pipelines/__fixtures__/azure-pipelines-invalid.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..aa326c7b7bd471083be062a76084c2ce9bdb1de3
--- /dev/null
+++ b/lib/manager/azure-pipelines/__fixtures__/azure-pipelines-invalid.yaml
@@ -0,0 +1,3 @@
+steps:
+- bash: echo "hello"
+  displayName: echo
diff --git a/lib/manager/azure-pipelines/__fixtures__/azure-pipelines-no-dependency.yaml b/lib/manager/azure-pipelines/__fixtures__/azure-pipelines-no-dependency.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f3b34ce08bf44a3ce37b380bf47f0283054c1d61
--- /dev/null
+++ b/lib/manager/azure-pipelines/__fixtures__/azure-pipelines-no-dependency.yaml
@@ -0,0 +1,7 @@
+resources:
+  pipelines:
+    - pipeline: MyAppA
+      source: MyCIPipelineA
+    - pipeline: MyAppB
+      source: MyCIPipelineB
+      trigger: true
diff --git a/lib/manager/azure-pipelines/__fixtures__/azure-pipelines.yaml b/lib/manager/azure-pipelines/__fixtures__/azure-pipelines.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8d61b6468d9e66429e040a1f69fc142f292f51f4
--- /dev/null
+++ b/lib/manager/azure-pipelines/__fixtures__/azure-pipelines.yaml
@@ -0,0 +1,14 @@
+resources:
+  repositories:
+    - type: github
+      name: renovate/renovate
+      ref: refs/heads/master
+    - type: github
+      name: user/repo
+      ref: refs/tags/v0.5.1
+  containers:
+    - container: linux
+      image: ubuntu:16.04
+    - container: python
+      image: python:3.7@sha256:3870d35b962a943df72d948580fc66ceaaee1c4fbd205930f32e0f0760eb1077
+    - container: missingimage
diff --git a/lib/manager/azure-pipelines/__snapshots__/extract.spec.ts.snap b/lib/manager/azure-pipelines/__snapshots__/extract.spec.ts.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1005f0dfae356811ef51d513a50da6144d4f53e9
--- /dev/null
+++ b/lib/manager/azure-pipelines/__snapshots__/extract.spec.ts.snap
@@ -0,0 +1,57 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`manager/azure-pipelines/extract extractContainer() should extract container information 1`] = `
+Object {
+  "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
+  "currentDigest": undefined,
+  "currentValue": "16.04",
+  "datasource": "docker",
+  "depName": "ubuntu",
+  "depType": "docker",
+  "replaceString": "ubuntu:16.04",
+}
+`;
+
+exports[`manager/azure-pipelines/extract extractPackageFile() extracts dependencies 1`] = `
+Array [
+  Object {
+    "autoReplaceStringTemplate": "refs/tags/{{newValue}}",
+    "currentValue": "v0.5.1",
+    "datasource": "git-tags",
+    "depName": "user/repo",
+    "depType": "gitTags",
+    "lookupName": "https://github.com/user/repo.git",
+    "replaceString": "refs/tags/v0.5.1",
+  },
+  Object {
+    "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
+    "currentDigest": undefined,
+    "currentValue": "16.04",
+    "datasource": "docker",
+    "depName": "ubuntu",
+    "depType": "docker",
+    "replaceString": "ubuntu:16.04",
+  },
+  Object {
+    "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
+    "currentDigest": "sha256:3870d35b962a943df72d948580fc66ceaaee1c4fbd205930f32e0f0760eb1077",
+    "currentValue": "3.7",
+    "datasource": "docker",
+    "depName": "python",
+    "depType": "docker",
+    "replaceString": "python:3.7@sha256:3870d35b962a943df72d948580fc66ceaaee1c4fbd205930f32e0f0760eb1077",
+  },
+]
+`;
+
+exports[`manager/azure-pipelines/extract extractRepository() should extract repository information 1`] = `
+Object {
+  "autoReplaceStringTemplate": "refs/tags/{{newValue}}",
+  "currentValue": "v1.0.0",
+  "datasource": "git-tags",
+  "depName": "user/repo",
+  "depType": "gitTags",
+  "lookupName": "https://github.com/user/repo.git",
+  "replaceString": "refs/tags/v1.0.0",
+}
+`;
diff --git a/lib/manager/azure-pipelines/extract.spec.ts b/lib/manager/azure-pipelines/extract.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a354466f09734087cd8da1c8a5c5640b461eb0ea
--- /dev/null
+++ b/lib/manager/azure-pipelines/extract.spec.ts
@@ -0,0 +1,103 @@
+import { readFileSync } from 'fs';
+import {
+  extractContainer,
+  extractPackageFile,
+  extractRepository,
+  parseAzurePipelines,
+} from './extract';
+
+const azurePipelines = readFileSync(
+  'lib/manager/azure-pipelines/__fixtures__/azure-pipelines.yaml',
+  'utf8'
+);
+
+const azurePipelinesInvalid = readFileSync(
+  'lib/manager/azure-pipelines/__fixtures__/azure-pipelines-invalid.yaml',
+  'utf8'
+);
+
+const azurePipelinesNoDependency = readFileSync(
+  'lib/manager/azure-pipelines/__fixtures__/azure-pipelines-no-dependency.yaml',
+  'utf8'
+);
+
+describe('manager/azure-pipelines/extract', () => {
+  it('should parse a valid azure-pipelines file', () => {
+    const file = parseAzurePipelines(azurePipelines);
+    expect(file).not.toBeNull();
+  });
+
+  it('return null on an invalid file', () => {
+    const file = parseAzurePipelines(azurePipelinesInvalid);
+    expect(file).toBeNull();
+  });
+
+  describe('extractRepository()', () => {
+    it('should extract repository information', () => {
+      expect(
+        extractRepository({
+          type: 'github',
+          name: 'user/repo',
+          ref: 'refs/tags/v1.0.0',
+        })
+      ).toMatchSnapshot();
+    });
+
+    it('should return null when repository type is not github', () => {
+      expect(
+        extractRepository({
+          type: 'bitbucket',
+          name: 'user/repo',
+          ref: 'refs/tags/v1.0.0',
+        })
+      ).toBeNull();
+    });
+
+    it('should return null when reference is not defined', () => {
+      expect(
+        extractRepository({
+          type: 'github',
+          name: 'user/repo',
+          ref: null,
+        })
+      ).toBeNull();
+    });
+
+    it('should return null when reference is invalid tag format', () => {
+      expect(
+        extractRepository({
+          type: 'github',
+          name: 'user/repo',
+          ref: 'refs/head/master',
+        })
+      ).toBeNull();
+    });
+  });
+
+  describe('extractContainer()', () => {
+    it('should extract container information', () => {
+      expect(
+        extractContainer({
+          image: 'ubuntu:16.04',
+        })
+      ).toMatchSnapshot();
+    });
+    it('should return null if image field is missing', () => {
+      expect(extractContainer({ image: null })).toBeNull();
+    });
+  });
+
+  describe('extractPackageFile()', () => {
+    it('returns null for invalid azure pipelines files', () => {
+      expect(extractPackageFile('')).toBeNull();
+    });
+    it('extracts dependencies', () => {
+      const res = extractPackageFile(azurePipelines);
+      expect(res.deps).toMatchSnapshot();
+      expect(res.deps).toHaveLength(3);
+    });
+    it('should return null when there is no dependency found', () => {
+      expect(extractPackageFile(azurePipelinesNoDependency)).toBeNull();
+    });
+  });
+});
diff --git a/lib/manager/azure-pipelines/extract.ts b/lib/manager/azure-pipelines/extract.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d94c3881277e73a789b59c380d93c7190c0c64c8
--- /dev/null
+++ b/lib/manager/azure-pipelines/extract.ts
@@ -0,0 +1,117 @@
+import { safeLoad } from 'js-yaml';
+import * as datasourceGitTags from '../../datasource/git-tags';
+import { logger } from '../../logger';
+import { PackageDependency, PackageFile } from '../common';
+import { getDep } from '../dockerfile/extract';
+
+interface Container {
+  image: string;
+}
+
+interface Repository {
+  type: 'git' | 'github' | 'bitbucket';
+  name: string;
+  ref: string;
+}
+
+interface Resources {
+  repositories: Repository[];
+  containers: Container[];
+}
+
+interface AzurePipelines {
+  resources: Resources;
+}
+
+export function extractRepository(
+  repository: Repository
+): PackageDependency | null {
+  if (repository.type !== 'github') {
+    return null;
+  }
+
+  if (!repository.ref?.startsWith('refs/tags/')) {
+    return null;
+  }
+
+  return {
+    autoReplaceStringTemplate: 'refs/tags/{{newValue}}',
+    currentValue: repository.ref.replace('refs/tags/', ''),
+    datasource: datasourceGitTags.id,
+    depName: repository.name,
+    depType: 'gitTags',
+    lookupName: `https://github.com/${repository.name}.git`,
+    replaceString: repository.ref,
+  };
+}
+
+export function extractContainer(
+  container: Container
+): PackageDependency | null {
+  if (!container.image) {
+    return null;
+  }
+
+  const dep = getDep(container.image);
+  logger.debug(
+    {
+      depName: dep.depName,
+      currentValue: dep.currentValue,
+      currentDigest: dep.currentDigest,
+    },
+    'Azure pipelines docker image'
+  );
+  dep.depType = 'docker';
+
+  return dep;
+}
+
+export function parseAzurePipelines(content: string): AzurePipelines | null {
+  let pkg = null;
+  try {
+    pkg = safeLoad(content);
+  } catch (err) /* istanbul ignore next */ {
+    logger.error({ err }, 'Error parsing azure-pipelines content');
+    return null;
+  }
+
+  if (!pkg || !pkg.resources) {
+    return null;
+  }
+
+  pkg.resources.containers = pkg.resources.containers || [];
+  pkg.resources.repositories = pkg.resources.repositories || [];
+
+  return pkg;
+}
+
+export function extractPackageFile(content: string): PackageFile | null {
+  logger.trace('azurePipelines.extractPackageFile()');
+  const deps: PackageDependency[] = [];
+
+  const pkg = parseAzurePipelines(content);
+  if (!pkg) {
+    return null;
+  }
+
+  // grab the repositories tags
+  for (const repository of pkg.resources.repositories) {
+    const dep = extractRepository(repository);
+    if (dep) {
+      deps.push(dep);
+    }
+  }
+
+  // grab the containers tags
+  for (const container of pkg.resources.containers) {
+    const dep = extractContainer(container);
+    if (dep) {
+      deps.push(dep);
+    }
+  }
+
+  if (!deps.length) {
+    return null;
+  }
+  return { deps };
+}
diff --git a/lib/manager/azure-pipelines/index.ts b/lib/manager/azure-pipelines/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..adbfba940a0e4158be1d67e9454d0bf1d9c706e9
--- /dev/null
+++ b/lib/manager/azure-pipelines/index.ts
@@ -0,0 +1,5 @@
+export { extractPackageFile } from './extract';
+
+export const defaultConfig = {
+  fileMatch: ['azure.*pipelines?.*\\.ya?ml$'],
+};
diff --git a/lib/manager/azure-pipelines/readme.md b/lib/manager/azure-pipelines/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..4207eae6e595535b8306c303867567408c05a583
--- /dev/null
+++ b/lib/manager/azure-pipelines/readme.md
@@ -0,0 +1,31 @@
+The `azure-pipelines` manager extracts container and repository resources from the `resources:` block. For example:
+
+```yaml
+resources:
+  repositories:
+    - type: github
+      name: renovate/renovate
+      ref: refs/heads/master
+    - type: github
+      name: user/repo
+      ref: refs/tags/v0.5.1
+  containers:
+    - container: linux
+      image: ubuntu:16.04
+    - container: python
+      image: python:3.7@sha256:3870d35b962a943df72d948580fc66ceaaee1c4fbd205930f32e0f0760eb1077
+```
+
+More about the resources block can be found on the [Azure pipelines documentation](https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema%2Cparameter-schema#resources).
+
+Files that are processed by the manager includes:
+
+- `.azure-pipelines/**/*.yaml`
+- `.azure-pipelines.yaml`
+- `.azure-pipelines.yml`
+- `azure-pipelines/**/*.yaml`
+- `azure-pipelines.yaml`
+- `azure-pipelines.yml`
+- `azure-pipeline/**/*.yaml`
+- `azure-pipeline.yaml`
+- `azure-pipeline.yml`